Mac: Dynamically configure Synergy to run on different networks and users

Batman

Over the last few weeks I've tried to figure out why Synergy (which had been installed by one user into the Applications directory) was unable to be opened by other users on the same machine. Initially I thought that there were file permission issue, but after changing them a few I was still unable to open the application. The solution to this problem also lead to more flexibility than before.

What I ended up doing was starting Synergy using a LaunchDaemon rather than just placing the application in the Login Items list (which loaded it after the user logged in). Besides the fact that I couldn't get the application to run on more than one user, if I had been able to do this, having it as two Login Items would have caused issues.

Be warned, I'm not that great at bash scripting, nor do I know how this will effect system performance after prolonged use. If you can see a better way of doing something, please comment with the suggestion.

First off, I needed to extract the binary and place it in a common location. Because I use MacPorts, I decided that /opt/local/ would be the best place to configure the application.

cp /Applications/Synergy.app/Contents/MacOS/synergyc /opt/local/sbin/synergyc
mkdir -p /opt/local/etc/synergy/conf/
mkdir /opt/local/etc/LaunchDaemons/com.symless.synergy/

Next thing was to create the script to not only launch synergyc, but monitor the network as well as user switches.

The reason why I wanted to monitor the network was due to the different Synergy setups that I have. I use Synergy both at home and work, so the main problem is that each setup has a different server IP. Additionally I didn't want Synergy to run while on foreign networks where I didn't need to have a Synergy server setup.

As for monitoring user switches, I recently came across a problem where if you ran Synergy under one user then switch to another user, the original "screen" was still registered with the server, but the new users screen was never registered on the server. To fix this I decided to keep tabs on the active user, and if they differed from the last time the script checked, restart Synergy to force the current screen to be registered.

vi /opt/local/etc/synergy/start.sh
chmod 0755 /opt/local/etc/synergy/start.sh

File: start.sh

#!/bin/bash

SYNERGYDIR=/opt/local/etc/synergy

GetNetworkIP()
{
   NETWORKIP=`ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'`
}
GetSynergyConfig()
{
   SYNERGYCONFIG=

   if [ -n "$NETWORKIP" ]; then
      if [ -f $SYNERGYDIR/$NETWORKIP.conf ]; then
         SYNERGYCONFIG=`cat $SYNERGYDIR/conf/$NETWORKIP.conf`
      fi
   fi
}
GetSynergyPID()
{
   SYNERGYPID=`pgrep synergyc`
}
GetUserCached()
{
   USERCACHED=

   if [ -f /tmp/synergy.user ]; then
      USERCACHED=`cat /tmp/synergy.user`
   fi
}
GetUserCurrent()
{
   USERCURRENT=`stat -f '%Su' /dev/console`
}
SetUserCached()
{
   echo $USERCURRENT > /tmp/synergy.user
}

GetNetworkIP

INTERVALS=0

while [ -z "$NETWORKIP" ]
do
   sleep 5

   GetNetworkIP

   let INTERVALS=INTERVALS+1

   if [ "$INTERVALS" -eq 12 ]; then
      exit 0
   fi
done

GetUserCached
GetUserCurrent

if [ "$USERCURRENT" != "root" ]; then
   if [ "$USERCACHED" != "$USERCURRENT" ]; then
      GetSynergyConfig

      if [ -n "$SYNERGYCONFIG" ]; then
         GetSynergyPID

         if [ -n "$SYNERGYPID" ]; then
            kill $SYNERGYPID
         fi

         /opt/local/sbin/synergyc $SYNERGYCONFIG

         SetUserCached
      fi
   fi
fi

Things to take note of:

  • While without a network it will retry every 5 seconds for a minute
  • If a config is unable to be found, Synergy isn't started

The configuration files are pretty simple to generate. Just create files with the same IP address you are assigned like so:

echo "-n MACHINENAME SERVERIP" > /opt/local/etc/synergy/conf/LOCALIP.conf

Last thing to do was to create and install the LaunchDaemon.

vi /opt/local/etc/LaunchDaemons/com.symless.synergy/com.symless.synergy.plist
ln -l /opt/local/etc/LaunchDaemons/com.symless.synergy/com.symless.synergy.plist /Library/LaunchDaemons/com.symless.synergy.plist
launchctl load /opt/local/etc/LaunchDaemons/com.symless.synergy/com.symless.synergy.plist

File: com.symless.synergy.plist

<?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>com.symless.synergy</string>
      <key>ProgramArguments</key>
      <array>
         <string>/bin/bash</string>
         <string>/opt/local/etc/synergy/start.sh</string>
      </array>
      <key>StartInterval</key><integer>30</integer>
      <key>KeepAlive</key><false/>
      <key>SuccessfulExit</key><true/>
   </dict>
</plist>

Things to take not of:

  • This daemon will keep running the script every 30 seconds. This is to keep track of the current user and restart Synergy upon user switch. launchd only allows one instance of a daemon to run at a time, so if the script gets locked up on network checking you shouldn't see multiple instances appear.