O'Reilly logo

Linux Multimedia Hacks by Kyle Rankin

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Hack #11. Automatically Synchronize Your Camera and Computer

With a custom hotplug script, you can automatically synchronize your computer and USB storage device camera just by plugging in the camera.

On a particular vacation where I brought both my laptop and my digital camera, I noticed I was offloading the day's pictures onto my laptop each night. The manual process was to plug in the camera, mount it as a USB storage device, create a new directory for the images, copy the images to the new directory, and, finally, unmount the camera. With a few tweaks to hotplug and a little detective work, I was able to make the entire process hands free: I now plug in the camera, and it automatically synchronizes everything for me. In this hack I describe the tweaks to hotplug, along with tips for creating your own custom synchronization script.

Configure Hotplug

Hotplug is a program under Linux that manages hot-pluggable devices. For the most part it is a program you don't have to think about—just plug in your USB mouse, for instance, and hotplug will make sure the applicable drivers are loaded. Hotplug is very powerful, however, in that it allows you to customize what to do when a certain device is plugged in. The first step to configuring hotplug is to plug in a camera and scan the system logs to make sure the camera is recognized. In the case of my camera, hotplug recognized that it was a USB storage device and made sure my usb-storage module was already loaded:

	Jan 19 15:46:27 clover kernel: hub.c: new USB device 00:02.0-1, assigned 
	address 4 
	Jan 19 15:46:27 clover kernel: WARNING: USB Mass Storage data integrity not 
	Jan 19 15:46:27 clover kernel: USB Mass Storage device found at 4 
	Jan 19 15:46:31 clover usb.agent[10819]: kernel driver usb-storage already 

USB drives (and in this case cameras that function as USB drives) work as regular SCSI hard drives in this situation and require the sd_mod module to be loaded. You could just mount the device that is created (/dev/sda1 typically, unless multiple drives are plugged in simultaneously), copy files, and be finished with the camera. But if you want to automatically synchronize this camera to your computer, you must perform special commands just for this drive, and not for any other USB storage device. To set up automatic synchronization, you first need some information from /proc. The /proc/bus/usb/devices file will show information about the various USB devices on the system. For instance, here is a snip from the file when my digital camera is plugged in:

	T: Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#= 2 Spd=12 MxCh= 0
	D: Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs= 1
	P: Vendor=07b4 ProdID=0105 Rev= 0.01
	S: Manufacturer=OLYMPUS	
	S: Product=C740UZ
	S: SerialNumber=000255534644
	C:* #Ifs= 1 Cfg#= 1 Atr=c0 MxPwr= 0mA
	I: If#= 0 Alt= 0 #EPs= 2 Cls=08(stor.) Sub=06 Prot=50 Driver=usb-storage
	E: Ad=04(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
	E: Ad=83(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms

Yeah, it's a lot of gibberish, but there is information in there that is useful for setting up hotplug. The parts that are of interest to you are Vendor=07b4, ProdID=0105, Product=C740UZ, and Driver=usb-storage. You can use these sections to configure hotplug to do certain things when this device is plugged in. Generally hotplug will detect that a device is a USB storage device automatically. In case your drive isn't automatically detected, you will have to add a configuration line for it in /etc/hotplug/usb/usb.usermap. The first four columns of usb.usermap are all that should concern you, and the information you need for those columns can be found in those special sections of the /proc/bus/usb/devices file. The first column contains the USB module to associate with the device, or what follows the Driver option (Driver=usb-storage). The second column uses 0x00f for all USB storage devices. The third and fourth options contain the hex code for the Vendor and Product ID respectively. The rest of the fields don't matter—the first three fields are enough to match this device—so put in 0x00 for those. For my camera, the file would look like this:

	# usb.usermap file 
	# This is autogenerated by update-usb.usermap program 
	# Note: you may use /etc/hotplug/usb/*.usermap 
	# usb module         match_flags idVendor idProduct bcdDevice_lo bcdDevice_ 
	hi bDeviceClass bDeviceSubClass 
	#bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol		driver_info 
	usb-storage    0x00f   0x07b4  0x0105 0x00   0x00     0x00   0x00    0x00 
	0x00    0x00   0x00

This line in usb.usermap tells hotplug to run the /etc/hotplug/usb/usb-storage script whenever it sees that this device is plugged in. That script can then load modules or run other programs (including setting up programs to run when the drive is removed). The next step is to create this file and add an entry that matches your camera based on the PRODUCT environment variable the hotplug script generates. Then create the directory in which the camera will be mounted (in this example /mnt/camera). The /etc/hotplug/usb/usb-storage script for my camera would look like this (replace username with your user's name):

	DEVICE=`grep "kernel: Attached scsi .*disk" /var/log/syslog | tail -n 1 |
	cut -f 10 -d " "`
	case "$PRODUCT" in
	# Olympus C750 camera
	   /bin/mount -t vfat /dev/${DEVICE}1 /mnt/camera
	   echo -e '#!/bin/sh\n/bin/umount /mnt/camera' > $REMOVER
	   chmod a+x $REMOVER
	   export DISPLAY=":0.0"
	   #su username -c /home/username/bin/camera_sync

The second line needs some explanation. USB drives are assigned SCSI drive designations on the fly starting from sda and going up. While I could just say /dev/sda1, if more than one USB device were plugged in at the time, the wrong device might get mounted. With the standard Linux device system, there isn't an easy way to determine what SCSI drive letter was assigned to the USB drive. A kludge around this fact is to simply grab the last mention of a USB SCSI drive assignment out of the system log and cut out the device information. Based on your kernel version, your system might log this information slightly differently, so you may have to compare the grep pattern to your syslog file and possibly adjust the -f 10 value to match the field that contains the SCSI device entry.

The PRODUCT environment variable specifies the Vendor and Product IDs for the current USB device. To see what kind of environment variables are present when this script is run, you can insert a set > /tmp/settings line above the case statement. Read through that file to see how PRODUCT is set for your product. In my case it was set to 7b4/105/1. Then set up the case statement to mount this camera when that device is actually plugged in to /mnt/camera. This method is a bit brittle, as you will see below, but it does work. Another environment variable, REMOVER, specifies the name of a script that is run after the device is removed. This script is empty by default, so I echoed in the umount command I wanted to use when I removed the drive.

Next make the script executable with this command:

	$ chmod a+x /etc/hotplug/usb/usb-storage

Then restart the hotplug service:

	$ /etc/init.d/hotplug restart

Now plug the camera and type df to confirm that /mnt/camera is mounted. After you unplug the drive, the drive will be umounted.

Use autofs Instead of Mounting Manually

There are some problems with the previous method. For one, the drive isn't unmounted until it already has been removed. This could result in file system corruption over time if the device failed to sync before being removed. The solution is to use autofs to mount the device on demand and then unmount when idle.

First, install the autofs system with your distribution's package manager. Then modify /etc/auto.master and add a line for your removable drives:

	# $Id: ch01.xml,v 1.2 2005/11/28 18:05:49 ellie Exp $
	# Sample auto.master file
	# Format of this file:
	# mountpoint map options
	# For details of the format look at autofs(5).
	/var/autofs/misc        /etc/auto.misc
	/var/autofs/net         /etc/auto.net
	/var/autofs/removable   /etc/auto.removable      --timeout=2

That last line tells autofs to mount any removable devices specified in /etc/auto.removable under /var/autofs/removable, and to unmount them after two seconds of idling. Now create the /etc/auto.removable file:

	sda      -fstype=vfat,umask=002      :/dev/sda1
	sdb      -fstype=vfat,umask=002      :/dev/sdb1
	sdc      -fstype=vfat,umask=002      :/dev/sdc1
	sdd      -fstype=vfat,umask=002      :/dev/sdd1

This file sets up mount points under /var/autofs/removable/, the mounting options to use, and indicates which device to mount. All of this happens outside /etc/fstab or any other mounting, so remove the /mnt/camera mount point. Instead, have the USB-storage hotplug script you created make a symlink to the autofs mount point when the drive is inserted, and then remove the symlink when the drive is removed. That way, you can deal only with /mnt/camera and not worry about /var/autofs directories. The new and improved /etc/hotplug/usb/usb-storage follows:

	DEVICE=`grep "kernel: Attached scsi .*disk" /var/log/syslog | tail -n 1 |
	cut -f 10 -d " "`
	case "$PRODUCT" in
	# Olympus C750 camera
	   ln -s /var/autofs/usb/$DEVICE/dcim/100olymp /mnt/camera
	   echo -e '#!/bin/sh\nrm /mnt/camera' > $REMOVER
	   chmod a+x $REMOVER
	   export DISPLAY=":0.0"
	   #su username -c /home/username/bin/camera_sync

Now, plug in the camera and confirm that /mnt/camera was created. In my case, I created the symlink to dig into the camera's directory structure and take me directly to the images (/dcim/100olymp). Change this directory path to match the path your camera uses. Because you are using autofs, the camera will not be mounted unless you access /mnt/camera. After two seconds, autofs will unmount the drive. You can monitor /var/log/syslog to watch this happening:

	Jan 19 16:24:35 clover automount[14059]: mount(generic): calling mkdir_path 
	Jan 19 16:24:35 clover automount[14059]: mount(generic): calling mount -t 
	vfat -s -o umask=002 
	/dev/sda1 /var/autofs/removable/sda 
	Jan 19 16:24:36 clover automount[14059]: mount(generic): mounted /dev/sda1 
	type vfat 
	on /var/autofs/removable/sda 
	Jan 19 16:24:39 clover automount[14066]: running expiration on path 
	Jan 19 16:24:39 clover automount[14066]: expired /var/autofs/removable/sda

As you can see, the drive unmounted seconds after the command finished since it had been idling. It would now be safe to remove the camera.

Make a Synchronization Script

Until now, the /etc/hotplug/usb/usb-storage script had the following line commented out:

	su username -c /home/username/bin/camera_sync

This line executes a custom camera syncing script as the normal user. This way you can change the script and add features without having to be root. Use su to change to your user from the root user so all of the images will be accessible by your normal user. The synchronization script relies on rsync to perform the synchronization logic, and the complete script looks like this:

	$DATE=`date +%Y-%m-%d` 
	mkdir -p ~/photos/$DATE 
	rsync -r --size-only -b --suffix="-1.jpg" /mnt/camera/ ~/photos/$DATE/

This script creates a new directory, named with today's date, under a photos directory I created in my home directory. Then rsync synchronizes the images with that directory according to their file sizes (since other Unix-style file data isn't present on the FAT32 drives most cameras use). The --suffix argument handles any potential duplicate files that may occur, in case your camera doesn't create unique-enough filenames across multiple flash cards. You can also launch a slideshow tool such as gThumb with this script and immediately look at thumbnails of all your photos. Once this script is created, uncomment the corresponding line from /etc/hotplug/usb/usb-storage and plug in your camera to test the synchronization. Any pictures on the camera will appear in a new directory under ~/photos.


If you don't clear your photos off the camera between syncs, plugging in the camera on a different day will cause this script to create a new directory containing the same photos.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required