If there is functionality that you need that does not exist within CCC, pre- and postflight shell scripts may be the solution for you. Preflight shell scripts run after CCC has performed "sanity" checks (e.g. are the source and destination volumes present?, is connectivity to a remote Macintosh established?) but before copying files. If you need your preflight script to run before CCC does the source/destination sanity checks, specify the preflight script as a global preflight script in the Advanced section of CCC's Settings window. Note that global preflight scripts run prior to every task, they are not task-specific. Also, please bear in mind that CCC automatically attempts to mount the source and destination at the beginning of the task, you should not be implementing a shell script to achieve that functionality. If you're having trouble with CCC pre-mounting the source and destination, please ask us for help rather than attempt to address the issue with a preflight shell script.
Postflight shell scripts run after CCC has finished copying files and performing its own internal cleanup, but before unmounting any volumes.
CCC passes several parameters to pre- and postflight shell scripts. For example, the following shell script:
#!/bin/sh
echo "Running $0"
echo `date`
echo "Source: $1"
echo "Destination: $2"
echo "Third argument: $3" # Exit status for postflight scripts, underlying volume path for a disk image for preflight scripts
echo "Fourth argument: $4" # Destination disk image path, if applicable
Would produce the following output (you can redirect this output to a file of your own specification) if implemented as a postflight script:
Running /Library/Application Support/com.bombich.ccc/Scripts/postaction.sh
Wed Oct 8 21:55:28 EDT 2014
Source: /
Destination: /Volumes/Offsite Backup
Third argument: 0
Fourth argument:
First parameter
The path to the source volume or folder. If the source volume is APFS-formatted, then this path will usually be the path to a temporary, read-only snapshot of the source (or the path to the source folder on the temporary, read-only snapshot). If the source volume is a macOS startup volume, CCC will send the path to a snapshot of the Data sibling of that volume as the first parameter.
Second parameter
The path to the destination volume or folder. If the destination is a disk image, this is the path to the mounted disk image. If the destination volume is a macOS System volume, CCC will send the path to the Data sibling of the destination as the second parameter, e.g. "/Volumes/Bootable Copy - Data".
Third parameter
- Preflight script: The underlying mountpoint for the volume that holds the destination disk image, if applicable.
- Postflight script: The exit status of the file copying phase of the backup task.
Fourth parameter
The path to the destination disk image, if applicable.
Controlling the CCC task via the preflight script exit status
If your preflight script exits with a non-zero exit status, it will cause CCC to abort the backup task. This can be used to your advantage if you want to apply preconditions to your backup operation. If you want to be certain that errors in your preflight shell script never cause the backup task to be aborted, add "exit 0" to the end of your script. If you would like that script to silently cancel the backup task, add "exit 89" to the end of the script. If the script is a global preflight script (specified in the Advanced section of CCC's Settings window), you can add "exit 104" to the end of the script to cancel the backup task and to avoid recording a Task History event.
The postflight script will run whether the backup task exits successfully or not. If your script should behave differently depending on the result of the task, you can test whether the third parameter is zero (an exit status of "0" means the task ended successfully). For example:
#!/bin/sh
source="$1"
dest="$2"
exitStatus=$3
if [ "$exitStatus" = "0" ]; then
# task succeeded
else
# task failed or reported errors
fi
If your postflight script exits with a non-zero exit status, CCC will not report this as a failure of the backup task. The failure will be noted in the Task History window, however.
Making changes to the source with a preflight script
If the source is an APFS volume, CCC will create a snapshot on that volume prior to running your preflight script, and then pass the path to that mounted snapshot as the first parameter to your shell script. Please bear this in mind if you are implementing a preflight script that makes changes to the source. Those changes will not be reflected in the current backup. If you need those changes to be reflected in the current backup, specify the preflight script as a global preflight script in the Advanced section of CCC's Settings window.
Running a preflight script prior to evaluating the source and destination availability
Per-task preflight scripts run after CCC has evaluated the availability of the source and destination. This order is deliberate — CCC passes the path of the source and destination to the preflight script, and we guarantee that these paths are available and correct when your preflight script is called. If you need your preflight script to make changes to the source, or take special measures to make the source or destination available (e.g. establishing a VPN connection), then you can perform those tasks in CCC's Global Preflight Script, specified in CCC Settings > Advanced. If you would like to limit the functionality of your global preflight script to a specific task, you can add logic to your script for that purpose. This example global preflight script demonstrates how to do this.
AppleScripts are not supported
You cannot specify an AppleScript as a pre- or postflight script, CCC currently only supports running shell scripts.
Shell scripts require a shell interpreter line
CCC does not assume a default shell environment when running your pre- or postflight script. Not doing so gives users a great deal of flexibility; they can choose to write their scripts in any shell or programming language (e.g. bash, python, perl, ruby, C). For CCC to execute a shell script as an application, though, the system needs to know what shell should be used to interpret the script, and that value needs to be defined in your shell script. This is done simply by placing a shell interpreter line at the top of the file, e.g. #!/bin/sh
.
Shell scripts run as the root user
CCC's pre- and postflight shell scripts are executed as the System Administrator (aka "root"). As such, any references to your own shell environment will be invalid. When referencing tools that lie outside of the default $PATH, be sure to either specify the full path to the item (e.g. /usr/local/bin/foo), or export your own $PATH at the top of your script. Likewise, if you make relative references to files (e.g. ~/Desktop/foo.log), those files will be created in the root user account, e.g. /var/root/Desktop/foo.log. Use absolute paths for more reliable results.
Another implication of running scripts as the root user is that interaction between the script and applications running via the logged-in user are generally not possible. For example, special steps are required if you want to open or close an application. See the quit_application.sh and open_application.sh scripts at the bottom of this document for an example of how to do this. Interaction with those applications usually will not work.
Security implications of pre- and postflight shell scripts
To prevent unauthorized modifications to your shell scripts, we recommend that you restrict the ownership and permissions of these scripts and to the folder in which they are contained. The parent folder and scripts should be writable only by the root user. For example, running the following in the Terminal application would secure any shell scripts located in the default location for pre- and postflight scripts:
sudo chown -R root:wheel /Library/Application\ Support/com.bombich.ccc/Scripts
sudo chmod -R 755 /Library/Application\ Support/com.bombich.ccc/Scripts
To further enhance the security of your pre and postflight scripts, CCC will require that scripts stored in the default location are owned by the root user and writable only by the root user, and that the Scripts folder itself is also owned and writable only by the root user. If a script that resides within the default Scripts folder does not meet these requirements, CCC will refuse to execute that script and the associated task will report an error.
After copying scripts into CCC's Scripts folder or making changes to those scripts, you can choose "Secure CCC's Scripts folder" from CCC's Utilities menu to correct any ownership or permissions concerns. Please note that these additional security requirements are only applied to scripts stored within the /Library/Application Support/com.bombich.ccc/Scripts folder. If you prefer to manage the security of your shell scripts on your own, you may store them in another location.
Example pre- and postflight shell scripts
To use any of these example scripts, download the script and place it somewhere on your startup disk. By default, CCC looks in /Library/Application Support/com.bombich.ccc/Scripts.
parallels_pause.sh
This is a preflight script that you can use to pause all currently-running Parallels VM containers. This script will also retain state information that can be read by the corresponding parallels_start.sh postflight script to resume these VMs after the backup task has completed. Note: This script relies on command-line tools offered only in Parallels Desktop for Mac Pro or Business Edition.
parallels_start.sh
This postflight script will resume any Parallels VM containers that were suspended by the parallels_pause.sh preflight script. Note: This script relies on command-line tools offered only in Parallels Desktop for Mac Pro or Business Edition.
play_sound.sh
If you want to play a unique sound, use this script. You can plug in the path to any audio file of your liking or try one of the examples included.
eject_source_and_destination.sh
CCC's option to automatically unmount the destination volume is a volume-level task, not a device task. It's also limited to the destination. If you want to eject the destination device, or if you want to unmount or eject the source, use this postflight script instead. Note that ejecting a device will unmount all volumes on the device. Also note that this example script adds a 60-second delay to accommodate snapshot creation on the destination.
pm_on_success.sh
This postflight script will perform the requested power management option (e.g. shutdown, restart, sleep) at the end of the backup task if the backup task completes without errors. Use this in lieu of one of the Power Management postflight options if you prefer the power management action does not occur when a task ends with errors (e.g. if the destination volume is missing).
quit_application.sh and open_application.sh
This pair of scripts can be used to quit and open an application before and after the backup task. Open these scripts in a text editor to define the application that should be quit or opened.
post_to_slack.sh
This postflight script will post the status of your backup task to a Slack channel.
ifttt_maker.sh
This postflight script will post an IFTTT Maker Event of the status of your backup task.