iPhone syncing and Linux

Note: installing iPhone updates through VirtualBox is not a good idea. Make sure you have a backup method to restore your phone before diving into this.

I love my iPhone, but I hate that I can’t sync it natively inside Linux. I was never able to get iTunes working running under Wine, so I’ve been forced to create a virtual machine running WinXP to sync it. I don’t like the idea of a VM running in the background, wasting system resources when it’s not being used. I wanted a better solution.

VirtualBox

With the help of udev and VirtualBox command-line tools, I was able to come up with something better. Now when I’m ready for bed I plug my iPhone in, VirtualBox automatically boots the VM, and it syncs with iTunes. When I unplug the phone, Windows shuts down automatically. The only time the VM is using system resources is while I’m sleeping, so I don’t care.

I think this is as good as it gets with the iPhone on Linux and the only compromise is the time invested to set it up.

To do this, you’ll first need to install the full version of Sun’s VirtualBox, it includes USB features that are required. It’s free for personal use. Create a new VM with a bare Windows install on it. I didn’t install any additional updates and I disabled Windows Update, since it’s behind a NAT and I won’t be doing anything other than the sync on it. I also disabled a bunch of unnecessary services and ran Bootvis to minimize the VM boot time. Then I mapped a network drive to my music folder (on the host system) so iTunes will have access to my entire music collection. I logged in with my iTunes account and resubscribed to all my podcasts. At this point it’s not a bad idea to make a copy of the VM in it’s pristine state.

VirtualBox Settings

Shut down Windows. In VirtualBox, right-click the VM and select Preferences. You should tell it to use VT-x/AMD-V usb(General > Advanced) if you have a relatively modern processor that supports virtualization extensions; it’s not a requirement but will improve performance. The settings you will need are under USB. Check “Enable USB Controller” and “Enable USB 2.0 EHCI Controller”, the click the plus icon to add a filter. While your iPhone is attached to the system, you should see it listed in the dropdown (Apple Inc. iPhone), select it and click OK. This is required so your VM can see the device. You might also want to configure a sound device (PulseAudio) or iTunes will complain.

Now we get to the fun stuff, tweaking the host Linux system and writing BASH scripts. First, let’s create a log file that anyone can write to in case we need to troubleshoot:

$ sudo touch /var/log/iphone.log

$ sudo chmod 777 /var/log/iphone.log

Now, we need to get the internal ID of the VM you created.

$ VBoxManage list vms

You should see the name of the new VM followed by it’s UUID in parenthesis. Copy that UUID, we’ll need it for our first script:

iphone_attach.sh

#!/bin/bash
export XAUTHORITY=/home/nathan/.Xauthority
export DISPLAY=:0.0
su nathan -c “/usr/bin/VBoxManage startvm bc341828-db3b-46a9-8bc9-153c8eb35ad7” >> /var/log/iphone.log

The two export lines tell the script which X Windows session to attach to. The final command uses the VBoxManage tools to start your VM, log the output, and do it under your own user account (since this will run as root). Obviously you’ll need to change “nathan” to your account name for each instance. You should also replace the UUID with your own. The remove script is not all too different:

iphone_remove.sh

#!/bin/bash
export XAUTHORITY=/home/nathan/.Xauthority
export DISPLAY=:0.0
su nathan -c “/usr/bin/VBoxManage controlvm bc341828-db3b-46a9-8bc9-153c8eb35ad7 acpipowerbutton” >> /var/log/iphone.log

Again, the export commands tell it which X session to use and we use VBoxManage to simulate an ACPI shutdown. You’ll need to replace the UUID with your own and change the user name and home folder path. Make sure these scripts work before you move on to the udev stuff.

grab the serial number

Note, this section was originally created using 0810 (Intrepid) but it broke in Jaunty (0904). I have another way to configure this so it works in Jaunty at the end of this post (it may also work in Interpid).

Now we need to tell Linux to run the above scripts when the device is connected/disconnected from the USB bus. First we need to find the serial number of your iPhone so we can tell udev what to look for.

$ lsusb | grep Apple

This displays the USB bus and device numbers for your phone, note the two 3-digit numbers and plug them into the next command.

udevinfo -a -p `udevinfo -q path -n /dev/bus/usb/004/002`|grep “ATTR{serial}”

Change 004 to the bus number you got in the previous command and change 002 to your device number. This digs into the attributes of your iPhone and displays the serial number which we’ll need later on. Note that you can remove the grep command to view all available attributes of your phone if you’re curious.

udev stuff

Go to the udev rules directory and create a new iphone rule, use a lower number like 98 so it gets processed after the other rules.

$ cd /etc/udev/rules.d

$ sudo vi 98-iphone.rules

98-iphone.rules

ACTION==”add”, SUBSYSTEM==”usb”, ATTR{serial}==”c4560xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”, SYMLINK+=”iphone”, RUN+=”/home/nathan/scripts/iphone_attach.sh”

ACTION==”remove”, SYMLINK==”iphone” ,RUN+=”/home/nathan/scripts/iphone_remove.sh”

The first line here describes what to look for when a device is attached and what to do when it finds your iPhone. The ACTION, SUBSYTEM, and ATTR declarations tell it to watch for a USB device being added with the serial number of your iPhone. SYMLINK tells it to create an entry on the dev file system for it (/dev/iphone); through trial and error I discovered that this is required so we have something to look for when the phone is disconnected. The RUN section tells it to run the iphone_attach.sh script.

The second line is a bit different and maybe not as intuitive. It is watching for the dev file of your iphone to disappear (/dev/iphone) which happens as soon as you unplug it. Then it runs the iphone_remove.sh script. That’s it, you’re done.

other stuff

One annoyance I ran into was Nautilus trying to automount the phone as a camera. I was unable to tell it to ignore the iPhone, so I just turned off automount completely in Nautilus using gconf-editor.

$ gconf-editor

(uncheck: apps > nautilus > preferences > media_automount)

Another idea I had to use the suspend/resume functionality instead of stopping/starting the VM. However, I found that on resume the VM wouldn’t properly sync with the phone until Windows rebooted, even after using the VBoxManage commands to disconnect/reconnect the phone.

itunesIn the future, I’d like to look into reducing the XP install size with something like nLite and using dropbox to move the VM to the cloud. The ultimate goal would be to have the ability to sync my phone from home, work, or my laptop while travelling. I have some ideas on the way to approach this but it’s not a burning need at the moment. It would be really cool though.

Jaunty

Unfortunately I noticed the iphone_remove.sh script was no longer triggering after I upgraded to Jaunty. So I figured out another way to configure udev. First, we need to come up with another identifier to use in the udev rule:

udevadm monitor –environment

While that command is running in the background, plug in your phone, one of the lines should look like this:

PRODUCT=5ac/1292/1

Copy this line. I’m not sure if the same ID applies to the original and 3G phones, so run this for yourself. Then we can create the udev rule.

vi /etc/udev/rules.d/98-iphone.rules

You may need to change the Product ID here if it differs from mine, and change the path to your script:

SUBSYSTEM==”usb”, ENV{PRODUCT}==”5ac/1292/1″, ACTION==”add”, RUN+=”/home/nathan/scripts/iphone_attach.sh”
SUBSYSTEM==”usb”, ENV{PRODUCT}==”5ac/1292/1″, ACTION==”remove”, RUN+=”/home/nathan/scripts/iphone_remove.sh”

And that’s it. This may actually be the proper way to configure the rules in Intrepid, but I no longer have a 0810 system to test on.

Advertisements

About this entry