Mounting an iPod/iPhone on a Linux device

By | February 3, 2011

These days mounting an iPod/iPhone/iPad on a Linux PC is an automatic task and all the synchronization operations, such as the music sync with Rythmbox, are supported or at least partially supported.

The communication with these devices can take place thanks to the libimobiledevice library with the help of fuse (filesystem in userspace) and several other libraries and applications. For a clearer picture of the involved libraries you can have a look at this software stack diagram.

Unfortunately, having the same functionality in a Linux embedded device such as a Set-Top-Box or a Digital Receiver is not easy because all the applications are part or depend strongly on GNOME or KDE that normally are not available in these systems.
However, all the libraries can be cross-compiled allowing to mount an iPod/iPhone/iPad as a storage device.
Of course, if you want to synchronize your data such as music or videos, you’ll have to develop your own application or port an existing one.

In this post I focus only on how to compile all the required libraries for mounting an iPod/iPhone/iPad as a storage device.
If the Set-Top-Box have a media player with the required codecs, they will be able, at least, to play the content.

Requirements

Fuse needs a kernel driver that is already included in the mainline kernel. In the kernel configuration you find this option under the Filesystem menu. You can compile it as a module or in-kernel. If you choose the former, the module will be called fuse.ko.

Environment configuration

Suppose that we want to install all the libraries in /mnt/target/usr/local.
/mnt/target is the top directory of the target’s filesystem that could be mounted via NFS.
Assume that the cross-toolchain (compiler, linker…) is already in your path.

Set the following environment variables:

$ export PREFIX=/mnt/target/usr/local
$ export HOST=sh4-linux
$ export BUILD=i386-linux
$ export LD_LIBRARY_PATH=$PREFIX/lib
$ export PKG_CONFIG_PATH=$LD_LIBRARY_PATH/pkgconfig


libusb

Package: libusb-1.0.8.tar.bz2

This package is required by libimobiledevice.

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX --disable-static --disable-log
$ make
$ make install

libplist

Package: libplist-1.3.tar.bz2

This package is required by libimobiledevice.

The compilation of libplist is different because it uses cmake.
Create a file toolchain.cmake with the following contents. Modify the cross-compiler variables according to your path:

# this one is important
SET(CMAKE_SYSTEM_NAME Linux)
#this one not so much
SET(CMAKE_SYSTEM_VERSION 1)

# specify the cross compiler
SET(CMAKE_C_COMPILER   /opt/STM/STLinux-2.3/devkit/sh4/bin/sh4-linux-gcc)
SET(CMAKE_CXX_COMPILER /opt/STM/STLinux-2.3/devkit/sh4/bin/sh4-linux-g++)

# where is the target environment 
SET(CMAKE_FIND_ROOT_PATH  /mnt/target/usr/local)

# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Then create the build directory, compile and install:

$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ..
$ make DESTDIR=$PREFIX install


usbmuxd

Package: usbmuxd-1.0.4.tar.bz2

This package is needed by libimobiledevice.

usbmux uses cmake too. Therefore, the procedure is the same as liplist:

Create the file toolchain.cmake with the same contents as with libplist-1.3 or just copy it to the current directory usbmuxd-1.0.4.

$ cd usbmuxd-1.0.4
$ cp ../libplist-1.3/toolchain.cmake .

Then create the build directory, compile and install:

$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ..
$ make DESTDIR=$PREFIX install

libgpg-error

Package: libgpg-error-1.7.tar.gz

This package is needed by libgcrypt.

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX
$ make
$ make install

libgcrypt

Package: libgcrypt-1.4.6.tar.gz

This package is needed by gnutls

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX --with-gpg-error-prefix=$PREFIX

Note: I didn’t need to modify these Makefiles when using an updated STLinux2.3. But if you haven’t done an ‘stmyum update’ lately, maybe you’ll need to modify them.
Edit the Makefile:
Remove from the variables DIST_SUBDIRS and SUBDIRS the directory ‘tests’

Edit the src/Makefile:
Set the following variables to the given values:

GPG_ERROR_CFLAGS = /mnt/target/usr/local/include
GPG_ERROR_CONFIG =
GPG_ERROR_LIBS = /mnt/target/usr/local/lib/libgpg-error.so.0.7.0
libgcrypt_la_LIBADD = 
	../cipher/libcipher.la 
	../random/librandom.la 
	../mpi/libmpi.la 
	/mnt/target/usr/local/lib/libgpg-error.so.0.7.0

Compile and install:

$ make
$ make install

libtans1

Package: libtasn1-2.7.tar.gz

This package is needed by libimobiledevice.

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX
$ make
$ make install

gnutls

Package: gnutls-2.8.6.tar.bz2

This package is needed by libimobiledevice.

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX 
--with-libgcrypt-prefix=$PREFIX --enable-large_files --disable-gtk-doc-html

Edit the files src/Makefile, doc/Makefile and doc/examples/Makefile:
Set LDFLAGS to this value:

LDFLAGS = /mnt/target/usr/local/lib/libgcrypt.so /mnt/target/usr/local/lib/libgpg-error.so
$ make
$ make install

libimobiledevice

Package: libimobiledevice-1.0.2.tar.bz2

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX 
libusbmuxd_CFLAGS="-I$PREFIX/include" libusbmuxd_LIBS="-L$PREFIX/lib" 
libgnutls_CFLAGS="-I$PREFIX/include" libgnutls_LIBS="-L$PREFIX/lib" 
libtasn1_CFLAGS="-I$PREFIX/include" libtasn1_LIBS="-L$PREFIX/lib" 
libplist_CFLAGS="-I$PREFIX/include" libplist_LIBS="-L$PREFIX/lib" 
libglib2_CFLAGS="-I$PREFIX/include -I$PREFIX/lib/glib-2.0/include" libglib2_LIBS="-L$PREFIX/lib" 
--without-swig

Edit the file tools/Makefile:
Set LDFLAGS to this value:

LDFLAGS = /mnt/target/usr/local/lib/libgcrypt.so /mnt/target/usr/local/lib/libgpg-error.so /mnt/target/usr/local/lib/libplist.so /mnt/target/usr/local/lib/libtasn1.so /mnt/target/usr/local/lib/libusbmuxd.so /mnt/target/usr/local/lib/libgnutls.so

Compile and install:

$ make
$ make install

fuse

Package: fuse-2.8.4

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX
$ make
$ make DESTDIR=$PREFIX install

ifuse

Package: ifuse-1.0.0.tar.bz2

$ ./configure --build=$BUILD --host=$HOST --prefix=$PREFIX 
CFLAGS=-D_FILE_OFFSET_BITS=64 
libimobiledevice_CFLAGS="-I$PREFIX/include" libimobiledevice_LIBS="-L$PREFIX/lib" 
libglib2_CFLAGS="-I$PREFIX/include/glib-2.0 -I$PREFIX/lib/glib-2.0/include" libglib2_LIBS="-L$PREFIX/lib" 
libgthread2_CFLAGS="-I$PREFIX/include" libgthread2_LIBS="-L$PREFIX/lib" 
libfuse_CFLAGS="-I$PREFIX/include" libfuse_LIBS="-L$PREFIX/lib"

Edit the file src/Makefile:
Set libfuse_LIBS to this value:

libfuse_LIBS = -L/mnt/target/usr/local/lib -lfuse -limobiledevice -lgnutls -lplist -lusbmuxd

Compile and install:

$ make
$ make install

Mounting the device

At this point you should be able to mount your iPod/iPhone as a storage device. Some iPods can have a partition, like /dev/sda1, formatted as VFAT of HFS+, depending on where you use it. Some others, like the iPod shuffle, doesn’t have a partition, so you’ll see them as /dev/sda.

Assuming that you want to mount it in /media/ipod, that it has partition /dev/sdb1, and it’s formatted in VFAT, you can mount it as a normal storage device:

$ mount -t vfat -o usefree /dev/sdb1 /media/ipod

For HFS+ is the same. Notice that your kernel must be compiled for supporting this filesystem:

$ mount -t hfsplus -o ro /dev/sdb1 /media/ipod

Now you can browse in /media/ipod and you’ll see the contents of your iPod’s filesystem!

References

5 thoughts on “Mounting an iPod/iPhone on a Linux device

  1. Honorroll

    Hi,
    Thanks for your information and it’s very useful.
    However, when i tried to configure libimobiledevice, i meet the error shown as below:
    checking consistency of all components of python development environment… no
    configure: error:
    Could not link test program to Python. Maybe the main Python library has been
    installed in some non-standard library path. If so, pass it to configure,
    via the LDFLAGS environment variable.
    Example: ./configure LDFLAGS=”-L/usr/non-standard-path/python/lib”
    ============================================================================
    ERROR!
    You probably have to install the development version of the Python package
    for your distribution. The exact name of this package varies among them.
    ============================================================================
    Do i have to compile any other sources like python2.6-dev?

    Really appreciate your help.

    Reply
    1. paguilar

      Hi,
      iirc, when I did the procedure in the post I already had Python installed (I compiled the source following this procedure). So, yes, you seem to need the Python development package. The mentioned procedure could solve your problem, or if you’re using a Linux distro that supports opkg or the like you could simply do opkg install package-name
      Regards.

      Reply
  2. Honnorroll

    I have installed python2.7 by cross-compiling, but the error still exists. Do i have to install python2.7-dev? Appreciate your help.

    Reply
    1. paguilar

      May be the problem is that the version of libimobiledevice is newer than the one I used. The newer version that you’re using is trying to link or even run a test for checking that Python is present, but since you’re cross-compiling, the test won’t work in your host. So may be the best thing you could do is to comment in the configure file this check and set to yes the variable used for saving the result of the test for avoiding future complains. Let’s hope this work.

      Reply
  3. soroosh

    i had same problem, i installed python2.6-dev and run again ./configure , error disappeared 😀
    [i have been using ubuntu 10.04 ]

    Reply

Leave a Reply to paguilar Cancel reply

Your email address will not be published. Required fields are marked *