Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

10.4: Back up files in the background using launchd System
Tiger only hintHaving benefited from this site many times, here is my first contribution.

Apple provides an example of how to automatically back up things using a Folder Action. This solution did not meet my needs, however, since:
  1. It doesn't work with FileVault turned on.
  2. It always copies everything in the set, whether or not is has changed since the last run.
  3. It only runs once when the backup disk is mounted.
Playing with launchd, bash, and perl, I came up with a solution that meets the following requirements:
  1. Continually creates a backup copy of all files in the backup set when and while a certain external medium is mounted.
  2. Updates only changed files.
  3. Runs in the background.
  4. Looks in one directory for files to be backed up.
  5. Follows aliases.
  6. Uses Spotlight to find additional files to back up.
So when I want to protect some file or directory, I either place an alias to it in ~/Auto Backup, or simply assign a color label to it. Every ten minutes, and also whenever a new Volume is mounted, launchd calls the ~/bin/autobackup script. If a specific Volume is present, it copies these files to it.

This may not be pretty code, but it works for me and also is quite flexible. The core is the following shell script:

#!/bin/bash

# This is ~/bin/autobackup

# All files matching this spotlight query will be backed up
# This example means: Everything that has a color label

QUERY="kMDItemFSLabel != '0'"

# Check if destination mounted and target folder available. If not, exit.
# DEST_FOLDER and BACKUP_FOLDER environment vars are passed to this script by launchd.

if [ ! -d $DEST_FOLDER ]; then exit 0; fi

# Find all items in BACKUP_FOLDER and pass them to 'autobackupitem.pl' perl scriptfind "$BACKUP_FOLDER" -regex "$BACKUP_FOLDER/[^/]*" -print0 | xargs -0 -n 1 -J/// $HOME/bin/autobackupitem.pl /// $DEST_FOLDER 2>/dev/null

# Find files matching $QUERY and pass them to 'autobackupitem.pl' perl script

mdfind -0 "$QUERY" | xargs -0 -n 1 -J/// $HOME/bin/autobackupitem.pl /// $DEST_FOLDER 2>/dev/null
exit 0

I want to follow aliases in $BACKUP_DIR to files I want to include in the backup set, so I need to use some Perl tricks to de-reference the alias. This is the Perl script called from the shell script above:

#!/usr/bin/perl

# This is ~/bin/autobackupitem.pl

# Thanks to http://use.perl.org/~pudge/journal/10437

use Mac::Errors;
use Mac::Files;
use Mac::Resources;

# Source path (may be an Alias)
my $path = $ARGV[0];

# Where to copy it
my $dest = $ARGV[1];

# If $path is an Alias, dereference it
my $link = $path;
my $alis;
my $res  = FSpOpenResFile($path, 0) or die $Mac::Errors::MacError;
# get resource by index; get first "alis" resource
my $alis = GetIndResource('alis', 1) or die $Mac::Errors::MacError;
if (! $?){
  $link = ResolveAlias($alis);
}
# Use rsync to actually copy it. Filenames may contain blanks, so use escaped quotes.
END { system "rsync -avuE --inplace \"$link\" \"$dest\""; }

Finally, in order to call ~/bin/autobackup, we need to configure launchd. Create a file containing the following code, and place it as Autobackup.plist in ~/Library/LaunchAgents:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>EnvironmentVariables</key>
        <dict>
                <key>BACKUP_FOLDER</key>
                <string>/Users/ar/Auto Backup</string>
                <key>DEST_FOLDER</key>
                <string>/Volumes/CFBackup/Backup</string>
                <key>HOME</key>
                <string>/Users/ar</string>
        </dict>
        <key>GroupName</key>
        <string>ar</string>
        <key>Label</key>
        <string>de.nvmr.autobackup</string>
        <key>Nice</key>
        <integer>12</integer>
        <key>OnDemand</key>
        <true/>
        <key>Program</key>
        <string>bin/autobackup</string>
        <key>RunAtLoad</key>
        <false/>
        <key>ServiceDescription</key>
        <string>Backup flagged files to external medium</string>
        <key>StartInterval</key>
        <integer>600</integer>
        <key>UserName</key>
        <string>ar</string>
        <key>WatchPaths</key>
        <array>
                <string>/Volumes</string>
        </array>
        <key>WorkingDirectory</key>
        <string>/Users/ar</string>
</dict>
</plist>

I use Lingon to create the launchd configuration and run it.
    •    
  • Currently 1.00 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (2 votes cast)
 
[19,697 views]  

10.4: Back up files in the background using launchd | 5 comments | Create New Account
Click here to return to the '10.4: Back up files in the background using launchd' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
10.4: Back up files in the background using launchd
Authored by: donquichote on Apr 04, '06 04:23:52AM

This one did not work for me. After loading the plist, the scripts copied about 81 folders and files, including some really old ones.



[ Reply to This | # ]
10.4: Back up files in the background using launchd
Authored by: arb on Apr 04, '06 07:21:46AM
Did you check the QUERY variable? The example I posted copies everything that has any color lable associated to it.

mdquery "kMDItemFSLabel != '0'"

shows you everything that would be copied apart from the stuff in the "Auto Backup" folder.



[ Reply to This | # ]

10.4: Back up files in the background using launchd
Authored by: rdrushal on Apr 05, '06 07:00:33PM

I had the same problem, but wish to disable the Spotlight search. Any suggestions as to how? I have been unable to hack it together so far...



[ Reply to This | # ]
10.4: Back up files in the background using launchd
Authored by: SeanAhern on Apr 13, '06 09:09:03AM

There's something funny going on in the first script, autobackup. You have a comment that begins "#Find all items in BACKUP_FOLDER"... But there's no code after that line. It would appear that your code got concatenated to the comment line. The code presumably begins with "perl scriptfind..." Thus, the code becomes:

perl scriptfind "$BACKUP_FOLDER" -regex "$BACKUP_FOLDER/[^/]*" -print0 | xargs -+0 -n 1 -J/// $HOME/bin/autobackupitem.pl /// $DEST_FOLDER 2>/dev/null

But this is still weird. No such "scriptfind" file exists in the system, and you didn't include it in the comment. Any suggestions here? Should this just be something like:

find $BACKUP_FOLDER -depth -print0 | xargs -0 -n1 -J/// $HOME/bin/autobackupitem.pl

[ Reply to This | # ]
10.4: Back up files in the background using launchd
Authored by: SeanAhern on Apr 13, '06 09:32:46AM

I think I found the answer (which should have been obvious to me, in retrospect). The line break should be here: "perl script<>find".



[ Reply to This | # ]