Media Transfer Protocol (MTP) was designed as a unified mean to access media on mobile devices and bring order in the world where each phone vendor used to have its own management software. With the wide spread of Android mobile devices, MTP gained popularity and after Android 4.1 vendors are typically setting it as default in their devices. MTP has major advantages to the previously used mass storage device mode: it provides access not only to the flash card, but also to the so-called internal memory of the device; and, it does not require the device to power off.
Linux have seen several implementations of MTP with libmtp being the most popular with recent distributions. However, libmtp is not suitable for more stable desktop distributions like RHEL 6 (and its derivatives); while libmtp itself can be built on RHEL 6, most applications which use it (e.g., gvfs-mtp layer for Gnome) require way too recent stack (Glib et al) which is unavailable on RHEL 6.
A suitable solution is to use the go-mtpfs FUSE module provided by a Google employee. It can help achieve a sleek plug-and-play performance for your phone while avoiding the hassle of never-actually-working file transfer over Bluetooth.
he go-mtpfs module has only significant requirement – a well working libusb1. RHEL 6 comes with version 1.0.9 while the current one is 1.0.16. An upgrade is possible:
- Fetch the latest source RPM file from Fedora 20 for package libusbx (it obsoletes libusb1 while providing same library) and install it locally.
- Edit the spec file and comment our the BuildRequire dependency on systemd-devel – it is a fake one (and systemd is not available on RHEL 6)
- Build with rpmbuild -bb.
- Install the libsusbx and libsusbx-devel packages (yum will remove your original libusb1 and libusb1-devel packages)
The go-mtpfs module is written in Go. There is a GCC-bsed go compiler, but it requires all files to be available locally. To speed up installation, use the golang compiler, provided by EPEL: yum install golang.
To fetch & compile all required sources and dependencies, now simply run these commands:
mkdir /tmp/go export GOPATH=/tmp/go go get github.com/hanwen/go-mtpfs # wait a few moments to compile cp /tmp/go/bin/go-mtpfs /usr/bin
FUSE is designed to run in userspace, but accessing your phone with user privileges seems difficult. To avoid many possible issues, set the module SUID root:
chmod 4755 /usr/bin/go-mtpfs.
The go-mtpfs will mount the device, but will not unmount it. For the latter, use the fusermount program. It is in /bin and is already SUID root, but is not available to users outside the fuse group. Either add your user to the fuse group and re-login, or simply run chmod 4755 /bin/fusermount.
You will need a permanent directory where your phone will be mounted. Make it where you like it (e.g., /mnt/phone), chown it to yourself and chmod it 777.
Finally, to make the plug-and-play magic, we’ll use udev. Udev executes a command when a device is added or removed from the system. Because the commands can only be simple ones and because we need to the run the mount command on behalf of the user that will access the phone, we’ll create two helper scripts – one to mount the phone (phone-mount.sh) and one to unmount it (phone-unmount.sh). Put them in /usr/bin and chmod them 755.
phone-mount.sh:
#/bin/bash # Export a suitable path - it is requred by the module, # but will not be supplied by the udev: export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin # Run the mounter as the user who will access the phone - # replace USER with your username su USER -c "/usr/bin/go-mtpfs /mnt/phone &" # Exiting is important, else udev may hang here forever exit
phone-unmount.sh:
#/bin/bash # Export a suitable path export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin # Run the FUSE unmounter /bin/fusermount -u /mnt/phone
Now, go to /etc/udev/rules.d directory and create a file named after your device, e.g. 99-phone.rules. Put inside two lines – one for mounting your device and one for unmounting it. Replace AAAA and BBBB with the vendor and product parts for your device – use lsusb when the device is plugged to find them out. (Note: when mounting, the device is already available and we can query iot for attributes like idVendor or idProduct; when unmountng, the device is already gone, so we can only use the environment variables supplied by the udev daemon.)
SUBSYSTEM=="usb", ATTRS{idVendor}=="AAAA", ATTRS{idProduct}=="BBBB", ACTION=="add", RUN+="/usr/bin/phone-mount.sh" ENV{ID_VENDOR_ID}=="AAAA", ENV{ID_MODEL_ID}=="BBBB", ACTION=="remove", RUN+="/usr/bin/phone-unmount.sh"
Voila, now your phone will be mounted when you plug it and unmounted when you unplug it!