Hotsyncing a Sony Clie under Linux

Traditionally, a usb hotsync solution under linux has involved an ugly solution. Plug in the usb device, wait for the device entries (ex: /dev/usb/0). Within a few seconds, start a client application, like pilot-xfer, to syncronise the palm databases between the two platforms. Alternatively, a client application polls for the creation of the usb device fifo, and then starts the transfer.

Neither of these two solutions is very good. I abhor unnessessary polling. It must be possible for the system to notify when a usb device is attached. And, in fact, it can. That’s one of Hotplug’s primary functions, after all.

This solution utilizes udev 087, hotplug 20040923-r1, and pilot-xfer 0.11.8, under the 2.6.15 kernel.

pilot-xfer, like many palm sync applications, requires a device to attach to. By default this application uses /dev/pilot, which works fine for our purposes. What we need, then, is a method by which to create a symlink between /dev/pilot and wherever our usb device was attached. It is not possible to predict this path inside dev in a changing system, so we’re going to make udev do the work for us.

By default, on my system, udev created inodes named /dev/tts/USBx, where x was some next-available integer. Using the following rule, we have asked udev to create a symlink /dev/pilot pointing to whatever inode is being created. We do not specify a NAME= paramater, utilizing the default.

/etc/udev/rules.d/pilot.rules
BUS=”usb” SYSFS{product}=”Palm Handheld*” MODE=”0600″ OWNER=”USERNAME” KERNEL=”ttyUSB*” SYMLINK=”pilot”

The Product name here will match many Palm Handheld-style devices, so you can tune the rule to match a specific make and model by using paramaters such as SYSFS{idVendor}="0x054c" and SYSFS{idProduct}="0x0066". Those id numbers can be found in /proc/bus/usb/devices. Additionally, use the options OWNER=”username”, GROUP=”groupname”, MODE=”0600″ to restrict permissions to a specific unix user or group.

So /dev/pilot is being created (with proper permissions) and removed on connect and detach of the usb device. If we wanted to start an application each time to handle data syncronization, this is where we would stop. However, the goal is to start and execute the sync automagically. Thus, we want to run a script to perform the hotsync now.

The script in /sbin/hotplug will run whenever a device is added or removed from the system. It will, in turn, execute every script matching /etc/hotplug.d/usb/*.hotplug. This script is run with the environment variables PRODUCT and ACTION defined.

/etc/hotplug.d/usb/clie.hotplug
#!/bin/sh

clie() {
echo 'Found a Sony Clie' | logger
(
for x in `seq 1 20`; do
[ -e /dev/pilot ] && break
sleep 1 # wait till /dev/pilot is created
done

# If still not created after 20 seconds, log error and fail.
if ! [ -e /dev/pilot ]; then
logger -p user.notice -t $0 -i - '/dev/pilot not created!'
exit 1
fi

# switch users, run pilot-xfer
su - USER -c /home/USER/bin/do_clie_hotsync.sh 2>&1 | logger -i -t clie.hotplug
) &
}

case $ACTION in
add) {
case $PRODUCT in
54c/66/100)  ## vendor and product IDs, from lsusb
clie
;;
esac
}
;;
remove)
## Fired when sync is done, too late for anything useful though.
;;
esac

If ACTION is ‘add‘ and PRODUCT is ‘54c/66/100‘ (vendor and product id), than the Sony Clie has been just been connected. switch/case style structures are used to ease extending this later. However, /dev/pilot does not yet exist at the time of invocation. So the script forks the process, waits until /dev/pilot is created (for 20 seconds), drops root privledges and become a normal user, runs the sync.

Usermap scrips ala /etc/hotplug/synce.usermap used to be utilized for this script-firing, but no longer.

/home/USER/bin/do_clie_hotsync.sh
#!/bin/sh

pilot-xfer --sync /home/USER/.clie  2>&1
echo Done sync!

This script, quite simply, starts pilot-xfer to do the actual transfer. Kept seperate to simplify.

Press the hotsync button on the Clie’s cradle, udev creates the inodes correctly, hotplug starts the handler script, waits for /dev/pilot to be created, and pilot-xfer is started to sync the data.

What else could we do? How about using mpg123(1) to play a chime when the hotsync is done.

Update: Please note that the relative versions of the kernel, hotplug and udev are important here. Apparently there have been some changes in the interface over time that can result in hotplug getting events for new devices and udev never creating the actual /dev/foo file.


About this entry