Expect command when triggered by launchd

Hi folks,

Im having trouble with an expect command in a shell script I use to back up mac os x servers. This one is being run on a 10.8.2 Server as part of a larger bash script. The script executes perfectly all the way through when triggered on the command line, but when launchd triggers it at the scheduled time, the rest of the script executes fine, but the expect command doesnt send the password and so the slapconfig command doesn't complete, it just hangs there waiting.

Here is the relevant portion of my script:

/usr/bin/expect -c '
spawn /usr/sbin/slapconfig -backupdb "'"${recover}/_OD_Backup_${date}"'"
sleep 10
expect "'"Enter archive password:"'"
send "'"${passwd}\\r"'"
interact
' >/Users/admin/Desktop/slapconfig.log

Ive redirected stdout to a text file to see where it stops and this is what it outputs:

"spawn /usr/sbin/slapconfig -backupdb /Volumes/RAID/Administration/Backups/server.domain.com/20121116/_OD_Backup_20121116
2012-11-17 00:06:42 +0000 slapconfig -backupdb
Enter archive password:
"

Perhaps this is a problem with launchd running the script commands in a subshell or something along those line? I'm a bit stumped why the expect command completes when the script is triggered on the command line but not when scheduled with launchd.

Any help would be greatly appreciated!

Often this sort of problem is caused by the lack of a controlling terminal. I am not a launchd user, but ssh has -t and -tt to force artficial controlling terminal generation. The -S sessiontype option looks promising.

What does your expect script exactly expect? Is the prompt the one expected?

Figured it out!

It wasnt anything about launchd session types or anything else. After reading a bit of the book "Exploring Expect", I followed up on a hint they gave about adding another expect line so the expect command doesnt end as soon as the first match is made and responded to. Here is the code that works, which is in a larger bash script:

/usr/bin/expect -c '
spawn slapconfig -backupdb "'"${recover}/_OD_Backup_${date}"'"
sleep 10
expect "Enter archive password:"
send "'"${passwd}\r"'"
expect "============"
' >${logfile}

For context, and hopefully to help other folks backing up mac servers, here is the larger bash script (which is a modified/updated older script I found online). It has been tested on 10.8.2 and works whether triggered via command line or launchdaemon (must be run as root). Adjust parameters at top of the script. The two variables with brackets (< and >) are required:

#!/bin/bash

# Path to the root folder where the backups will be stored
# This path should not be on the root volume, and not accessible
# to non-administrators

recover_path="<path/to/backup/folder>"

# Log file location

logfile="/Library/Logs/Server_Backup.log"

# You can either backup all of the services (even those not in use)
# or you can specify which services you want to backup.

# Path to serveradmin command

serveradmincmd="/Applications/Server.app/Contents/ServerRoot/usr/sbin/serveradmin"

services=`$serveradmincmd list`
#services="afp ipfilter smb"

# This is the password you will use to recover your OD sparseimage.
# It should NOT be the same as your Directory Administrator password
# for security reasons.

passwd="<password>"

# Number of days worth of backups to keep

backupdays="30"

###############################################################
#### Advanced modification only. The rest can be left as is ###
###############################################################

# This is the hostname of the server the script is running on
# This variable is used so that the same script can be run
# from multiple servers on a single share point
server=`hostname`

# Purge backups older than the amount of days user has set above

find "${recover_path}/$server/"* -maxdepth 0 -mtime +$backupdays -print | xargs rm

# Get today's date and format it as YYYYMMDD
date=`date ''+%c%m%d'' | awk '{printf $5}'`

# Set the full path to where this days backups will be stored
recover=${recover_path}/$server/$date

mkdir -p "${recover}"
chmod 600 "${recover}"

# grab the server configuration plists
for service in $services; do
    $serveradmincmd settings $service > "${recover}/$service.txt"
    sleep 1
done

# Backup Open Directory

/usr/bin/expect -c '
spawn slapconfig -backupdb "'"${recover}/_OD_Backup_${date}"'"
sleep 10
expect "Enter archive password:"
send "'"${passwd}\r"'"
expect "============"
' >${logfile}

echo "Script Complete at `date`" >>${logfile}
exit 0

So, your expectations were thrown off by quoting and escqping? Well, that's layering for you. Good luck!

Not quite. I had been playing around with escaping and quoting and that wasn't the piece I was missing. The problem was that as soon as the first expect pattern was matched, and the appropriate response sent, the expect command exited, giving no time for the actual spawned process to run and complete. Adding another expect pattern that will not be matched means the expect command runs until it times out looking for that pattern. This approach gives us enough time for the spawned process (slapconfig) to conplete.

Not sure why it reacts differently based on launchd trigger, but this solution works.