I'm having issues with launchd. I have 2 external hdds, one that stores data, the other that's used for backup.
I store my data on encrypted sparsebundles, 6 in total.
I backup to encrypted sparsebundles: 6 corresponding to the data bundles above, and 3 more for my 3 filevault protected accounts.
I have written a series of scripts that will automount these sparsebundles.
If i launch the scripts manually everything works as expected.
If i set up a launchd plist to run when it detects the external drives it launches the script fine, but the volumes never mount.
The scripts require admin privileges (for security) so i've placed the launchd plist in /Library/LaunchDaemons.
To summarise, the launch daemon launches my script fine, the command to mount is executed with root permissions and logged to the terminal, but nothing ever mounts ..
i'm really at a loss - any ideas?
Here is the launchd script i'm using ..
Here are the scripts if it's useful to see them .. These are the common commands shared across both scripts, in the file at /Extensions/System/Encrypted Sparsebundles/Common Functions.sh
These are the mount commands, in the file at /Extensions/System/Encrypted Sparsebundles/Mount Commands.sh
I store my data on encrypted sparsebundles, 6 in total.
I backup to encrypted sparsebundles: 6 corresponding to the data bundles above, and 3 more for my 3 filevault protected accounts.
I have written a series of scripts that will automount these sparsebundles.
If i launch the scripts manually everything works as expected.
If i set up a launchd plist to run when it detects the external drives it launches the script fine, but the volumes never mount.
The scripts require admin privileges (for security) so i've placed the launchd plist in /Library/LaunchDaemons.
To summarise, the launch daemon launches my script fine, the command to mount is executed with root permissions and logged to the terminal, but nothing ever mounts ..
i'm really at a loss - any ideas?
Here is the launchd script i'm using ..
Code:
<?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>Label</key>
<string>me.test.AutomountExternalVolumes</string>
<key>ProgramArguments</key>
<array>
<string>/Extensions/System/Encrypted Sparsebundles/Mount Commands.sh</string>
</array>
<key>WatchPaths</key>
<array>
<string>/Volumes</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<false/>
</dict>
</plist>
Here are the scripts if it's useful to see them .. These are the common commands shared across both scripts, in the file at /Extensions/System/Encrypted Sparsebundles/Common Functions.sh
Code:
#!/bin/sh
# Set of shared functions common to mounting and unmounting tasks.
## GENERAL ##
diskHasUUID()
{
disk_name=${1}; disk_uuid=${2}
# make sure $disk_name isn't empty
if [[ "${disk_name}" ]]; then
name_uuid=`diskutil info "${disk_name}" | awk '/Volume UUID/ {print $3}'`
if [[ "${name_uuid}" == "${disk_uuid}" ]]; then
echo "true"
else
echo "false"
fi
fi
}
volumeIsMounted()
{
volume=${1}
# make sure $volume isn't empty
if [[ "${volume}" ]]; then
mount | grep "${volume} (" > /dev/null
if [[ ${?} == 0 ]]; then
echo "true"
else
echo "false"
fi
fi
}
mountStatus()
{
status_file=${1};
if [[ -f "${status_file}" ]]; then
echo `cat "${status_file}"`
else
sudo echo "Unmounted" > "${status_file}"
echo "Unmounted"
fi
}
updateMountStatus()
{
status_file=${1}; status=${2}
if [[ `mountStatus "${status_file}"` != "${status}" ]]; then
sudo echo "${status}" > "${status_file}"
fi
}
## MOUNTING ##
mountVolume()
{
sparsebundle_path=${1}; mount_point=${2}
sudo hdiutil attach -nobrowse "${sparsebundle_path}" -mountpoint "${mount_point}" > /dev/null
}
launchUsersOnMountDiskScript()
{
# launch user scripts to perform custom actions on mount
scripts_path=${1}; disk_script=${2}
personal_script="/Users/Personal/${scripts_path}/${disk_script}"
university_script="/Users/University/${scripts_path}/${disk_script}"
work_script="/Users/Work/${scripts_path}/${disk_script}"
if [[ -f "${personal_script}" ]]; then
sudo sh "${personal_script}"
fi
if [[ -f "${university_script}" ]]; then
sudo sh "${university_script}"
fi
if [[ -f "${work_script}" ]]; then
sudo sh "${work_script}"
fi
}
mountSparsebundle()
{
volume_path=${1}; disk_name=${2}; mount_path=${3}; sparsebundle=${4};
status_file="/${volume_path}/${disk_name}/.${mount_path}/Mount Status"
if `volumeIsMounted "${mount_path}"`; then
updateMountStatus "${status_file}" "Mounted"
echo "[Did NOT Mount Volume:] ${sparsebundle} on disk ${disk_name}, it is already mounted."
else
# check for a hdiutil attach process with the sparsebundles path, if a process exists
# a compaction of the sparsebundle is in progress and we should quit.
ps -Af | grep "hdiutil attach" | grep "${sparsebundle}" | grep -v "grep" > /dev/null
if [[ ${?} == 0 ]]; then
updateMountStatus "${status_file}" "Unmounted"
echo "[Did NOT Mount Volume:] ${sparsebundle} on disk ${disk_name}, sparsebundle is being mounted by another process."
exit 0
fi
sparsebundle_path="/${volume_path}/${disk_name}/.${mount_path}/${sparsebundle}"
# check for a hdiutil compact process with the sparsebundles path, if a process exists
# a compaction of the sparsebundle is in progress and we should quit.
ps -Af | grep "hdiutil compact ${sparsebundle_path}" | grep -v "grep" > /dev/null
if [[ ${?} == 0 ]]; then
updateMountStatus "${status_file}" "Unmounted"
echo "[Did NOT Mount Volume:] ${sparsebundle} on disk ${disk_name}, sparsebundle is being compacted."
exit 0
fi
echo "[Attempting to Mount Volume:] ${sparsebundle} on disk ${disk_name}."
mount_point="/${volume_path}/${disk_name}/${mount_path}"
mountVolume "${sparsebundle_path}" "${mount_point}"
if `volumeIsMounted "${mount_path}"`; then
updateMountStatus "${status_file}" "Mounted"
echo "[Mounted Volume:] ${sparsebundle} on disk ${disk_name}."
scripts_path="Library/Scripts/Applications/Bash/External Disk/On Mount"
disk_script="${disk_name}/${mount_path}.sh"
launchUsersOnMountDiskScript "${scripts_path}" "${disk_script}"
else
updateMountStatus "${status_file}" "Unmounted"
echo "[Did NOT Mount Volume:] ${sparsebundle} on disk ${disk_name}, unknown error."
fi
fi
}
## UNMOUNTING ##
unmountVolume()
{
mount_point=${1}
sudo hdiutil detach "${mount_point}" > /dev/null
}
launchUsersBeforeUnmountDiskScript()
{
# launch user scripts to perform custom actions on mount
scripts_path=${1}; disk_script=${2}
personal_script="/Users/Personal/${scripts_path}/${disk_script}"
university_script="/Users/University/${scripts_path}/${disk_script}"
work_script="/Users/Work/${scripts_path}/${disk_script}"
if [[ -f "${personal_script}" ]]; then
sudo sh "${personal_script}"
fi
if [[ -f "${university_script}" ]]; then
sudo sh "${university_script}"
fi
if [[ -f "${work_script}" ]]; then
sudo sh "${work_script}"
fi
}
quitAllApplicationsAccessingVolume()
{
volume=${1}
for process in `lsof -t "/${volume}"`; do
application=`ps acx | awk '{ if ($1 == '${process}') print $5 }'`
osascript -e "/Extensions/User/Application Controls/Quit & Save.scpt" "${application}" "save-true"
done
}
unmountSparsebundle()
{
volume_path=${1}; disk_name=${2}; mount_path=${3}; sparsebundle=${4}; compact=${5};
status_file="/${volume_path}/${disk_name}/.${mount_path}/Mount Status"
if `volumeIsMounted "${mount_path}"`; then
scripts_path="Library/Scripts/Applications/Bash/External Disk/On Unmount"
disk_script="${disk_name}/${mount_path}.sh"
launchUsersBeforeUnmountDiskScript "${scripts_path}" "${disk_script}"
#quitAllApplicationsAccessingVolume "${mount_point}"
echo "[Attempting to Unmount Volume:] ${sparsebundle} on disk ${disk_name}."
mount_point="/${volume_path}/${disk_name}/${mount_path}"
unmountVolume "${mount_point}"
if `volumeIsMounted "${mount_path}"`; then
updateMountStatus "${status_file}" "Mounted"
echo "[Did NOT Unmount Volume:] ${sparsebundle} on disk ${disk_name}, unknown error."
else
if "${compact}"; then
sparsebundle_path="/${volume_path}/${disk_name}/.${mount_path}/${sparsebundle}"
compactVolume "${sparsebundle_path}"
echo "[Volume Compacted:] ${sparsebundle} on disk ${disk_name}."
fi
updateMountStatus "${status_file}" "Unmounted"
echo "[Volume Unmounted:] ${sparsebundle} on disk ${disk_name}."
fi
else
updateMountStatus "${status_file}" "Unmounted"
echo "[Did NOT Unmount Volume:] ${sparsebundle} on disk ${disk_name}, it's already unmounted."
fi
}
compactVolume()
{
sparsebundle_path=${1};
sudo hdiutil compact "${sparsebundle_path}" > /dev/null
}
ejectDisk()
{
volume_path=${1}; disk_name=${2}
if `volumeIsMounted "${disk_name}"`; then
sudo diskutil eject "/${volume_path}/${disk_name}" > /dev/null
if `volumeIsMounted "${disk_name}"`; then
echo "[Failed to Ejected Disk:] ${disk_name}"
else
echo "[Ejected Disk:] ${disk_name}"
fi
fi
}
ejectDiskOnUnmountsComplete()
{
volume_path=${1}; disk_name=${2}; sparsebundles=${3}
mount_path="/${volume_path}/${disk_name}"
for mount_point in `eval echo ${sparsebundles}`; do
# replace dashes (-) with spaces
mount_point=`echo ${mount_point} | sed 's/-/ /g'`
mount_status=`cat "${mount_path}/.${mount_point}/Mount Status"`
while [[ "${mount_status}" != "Unmounted" ]]; do
sleep 1
mount_status=`cat "${mount_path}/.${mount_point}/Mount Status"`
done
done
ejectDisk "${volume_path}" "${disk_name}"
}
These are the mount commands, in the file at /Extensions/System/Encrypted Sparsebundles/Mount Commands.sh
Code:
#!/bin/sh
# Script to mount all specified encrypted sparsebundles at the specified paths.
# Can also define custom commands on each volumes mount.
## GENERAL ##
# must run script as root.
if [[ `id -u` != 0 ]]; then
echo " [USAGE:] Script must be run with admin priviledges."
exit -1
fi
# directory housing all neccesary files.
# required so that launchd plists will be able to locate
# everything they need wherever they are launched from.
directory="/Extensions/System/Encrypted Sparsebundles"
# set of shared functions common to mounting and unmounting tasks.
source "${directory}/Common Functions.sh"
## MAIN ##
## Beta Aquarii (Internal)
disk_name="Beta Aquarii"
# check the disk named $disk_name is in fact the disk we think it is.
if `diskHasUUID "${disk_name}" "8EB6A1B8-2D69-3154-A1B9-7061BAE27699"`; then
# volume path and disk name for the internal disk need to be blank.
volume_path=""; disk_name=""
mount_path="Virtual Machines"
sparsebundle="Encrypted Virtual Machines.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
fi
## Delta Aquarii (Marchmont Data Store)
disk_name="Delta Aquarii"
# check the disk named $disk_name is actually mounted, and is in fact the disk we think it is.
if `volumeIsMounted "${disk_name}"` && \
`diskHasUUID "${disk_name}" "7FC856A4-086A-39DA-BB49-FBD5EF42F34D"`; then
volume_path="Volumes"
# Documents
mount_path="Documents"
sparsebundle="Encrypted Documents.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Movies
mount_path="Movies"
sparsebundle="Encrypted Movies.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Music
mount_path="Music"
sparsebundle="Encrypted Music.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Software
mount_path="Software"
sparsebundle="Encrypted Software.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# To Sort
mount_path="To Sort"
sparsebundle="Encrypted To Sort.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Torrents
mount_path="Torrents"
sparsebundle="Encrypted Torrents.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
fi
## Zeta Aquarii (Marchmont Backup)
disk_name="Zeta Aquarii"
# check the disk named $disk_name is actually mounted, and is in fact the disk we think it is.
if `volumeIsMounted "${disk_name}"` && \
`diskHasUUID "${disk_name}" "FD549F08-B7C5-3D85-B4DA-67E747B1316B"`; then
volume_path="Volumes"
# Beta Aquarii - Personal Backup
mount_path="Beta Aquarii Backup/Personal Backup"
sparsebundle="Personal Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Beta Aquarii - University Backup
mount_path="Beta Aquarii Backup/University Backup"
sparsebundle="University Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Beta Aquarii - Work Backup
mount_path="Beta Aquarii Backup/Work Backup"
sparsebundle="Work Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Delta Aquarii - Documents
mount_path="Delta Aquarii Backup/Documents Backup"
sparsebundle="Documents Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Delta Aquarii - Movies
mount_path="Delta Aquarii Backup/Movies Backup"
sparsebundle="Movies Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Delta Aquarii - Music
mount_path="Delta Aquarii Backup/Music Backup"
sparsebundle="Music Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Delta Aquarii - Software
mount_path="Delta Aquarii Backup/Software Backup"
sparsebundle="Software Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Delta Aquarii - To Sort
mount_path="Delta Aquarii Backup/To Sort Backup"
sparsebundle="To Sort Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Delta Aquarii - Torrents
mount_path="Delta Aquarii Backup/Torrents Backup"
sparsebundle="Torrents Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
fi
## Alpha Aquarii (Forum Backup)
disk_name="Alpha Aquarii"
# check the disk named $disk_name is actually mounted, and is in fact the disk we think it is.
if `volumeIsMounted "${disk_name}"` && \
`diskHasUUID "${disk_name}" "B79B8E10-AC24-3D93-9F6E-5B5A8A594CB7"`; then
volume_path="Volumes"
# Personal Incremental Backup
mount_path="Personal Incremental Backup"
sparsebundle="Personal Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# University Incremental Backup
mount_path="University Incremental Backup"
sparsebundle="University Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Work Incremental Backup
mount_path="Work Incremental Backup"
sparsebundle="Work Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
fi
## Tau Aquarii (Mobile Backup)
disk_name="Tau Aquarii"
# check the disk named $disk_name is actually mounted, and is in fact the disk we think it is.
if `volumeIsMounted "${disk_name}"` && \
`diskHasUUID "${disk_name}" "5294130A-E658-3D82-B722-E17829FA6555"`; then
volume_path="Volumes"
# Personal Incremental Backup
mount_path="Personal Incremental Backup"
sparsebundle="Personal Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# University Incremental Backup
mount_path="University Incremental Backup"
sparsebundle="University Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
# Work Incremental Backup
mount_path="Work Incremental Backup"
sparsebundle="Work Encrypted Backup.sparsebundle"
mountSparsebundle "${volume_path}" "${disk_name}" "${mount_path}" "${sparsebundle}" &
fi
exit 0
Last edited by a moderator: