2f74e09
usbscsi: Switch from lockdev to flock
2f74e09
2f74e09
Currently there are 2 problems with the lockdev usage in usbscsi:
2f74e09
1) It breaks usbscsi completely due to a missing symbol when dlopening
2f74e09
   usbscsi.so, which is caused by libgphoto2_port/usbscsi/Makefile-files not
2f74e09
   adding $(SERIAL_LIBS) to usbscsi_la_LIBADD
2f74e09
2) lockdev uses /var/lock/lockdev, which by default is:
2f74e09
   drwxrwxr-x. 2 root lock 40 Sep 19 22:49 /var/lock/lockdev
2f74e09
   So despite our udev rules, gphoto using apps need to run as
2f74e09
   root (or group lockdev) to be able to work with usbscsi port devices
2f74e09
2f74e09
I've decided to fix 2) by moving to flock, lockdev makes sense for serial
2f74e09
ports, since other programs may be trying to access them at the same time,
2f74e09
for usbscsi however we only need to coordinate with other apps also using
2f74e09
libgphoto2, and flock then suffices, is much simpler and does not have
2f74e09
the rights issues of lockdev. This fix for 2), also fixes 1) by simply no
2f74e09
longer needing lockdev.
2f74e09
2f74e09
Index: libgphoto2_port/usbscsi/linux.c
2f74e09
===================================================================
2f74e09
--- libgphoto2_port/usbscsi/linux.c	(revision 14108)
2f74e09
+++ libgphoto2_port/usbscsi/linux.c	(working copy)
2f74e09
@@ -1,6 +1,6 @@
2f74e09
 /* SCSI commands to USB Mass storage devices port library for Linux
2f74e09
  * 
2f74e09
- *   Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
2f74e09
+ *   Copyright (c) 2010-2012 Hans de Goede <hdegoede@redhat.com>
2f74e09
  *
2f74e09
  * This program is free software; you can redistribute it and/or modify
2f74e09
  * it under the terms of the GNU Lesser General Public License as published by
2f74e09
@@ -19,6 +19,7 @@
2f74e09
 #include "config.h"
2f74e09
 #include <gphoto2/gphoto2-port-library.h>
2f74e09
 
2f74e09
+#include <errno.h>
2f74e09
 #include <stdio.h>
2f74e09
 #include <stdlib.h>
2f74e09
 #include <unistd.h>
2f74e09
@@ -29,6 +30,7 @@
2f74e09
 #ifdef HAVE_LIMITS_H
2f74e09
 # include <limits.h>
2f74e09
 #endif
2f74e09
+#include <sys/file.h>
2f74e09
 #include <sys/stat.h>
2f74e09
 #include <sys/types.h>
2f74e09
 #ifdef HAVE_SYS_PARAM_H
2f74e09
@@ -40,9 +42,6 @@
2f74e09
 #ifdef HAVE_SCSI_SG_H
2f74e09
 # include <scsi/sg.h>
2f74e09
 #endif
2f74e09
-#ifdef HAVE_LOCKDEV
2f74e09
-#  include <lockdev.h>
2f74e09
-#endif
2f74e09
 
2f74e09
 #include <gphoto2/gphoto2-port-result.h>
2f74e09
 #include <gphoto2/gphoto2-port-log.h>
2f74e09
@@ -80,62 +79,37 @@
2f74e09
 }
2f74e09
 
2f74e09
 static int
2f74e09
-gp_port_usbscsi_lock (GPPort *port, const char *path)
2f74e09
+gp_port_usbscsi_lock (GPPort *port)
2f74e09
 {
2f74e09
-#ifdef HAVE_LOCKDEV
2f74e09
-	int pid;
2f74e09
-
2f74e09
 	gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
2f74e09
-		"Trying to lock '%s'...", path);
2f74e09
+		"Trying to lock '%s'...", port->settings.usbscsi.path);
2f74e09
 
2f74e09
-	pid = dev_lock (path);
2f74e09
-	if (pid) {
2f74e09
-		if (port) {
2f74e09
-			if (pid > 0)
2f74e09
-				gp_port_set_error (port, _("Device '%s' is "
2f74e09
-					"locked by pid %d"), path, pid);
2f74e09
-			else
2f74e09
-				gp_port_set_error (port, _("Device '%s' could "
2f74e09
-					"not be locked (dev_lock returned "
2f74e09
-					"%d)"), path, pid);
2f74e09
+	if (flock(port->pl->fd, LOCK_EX | LOCK_NB) != 0) {
2f74e09
+		switch (errno) {
2f74e09
+		case EWOULDBLOCK:
2f74e09
+			gp_port_set_error (port,
2f74e09
+				_("Device '%s' is locked by another app."),
2f74e09
+				port->settings.usbscsi.path);
2f74e09
+			return GP_ERROR_IO_LOCK;
2f74e09
+		default:
2f74e09
+			gp_port_set_error (port,
2f74e09
+				_("Failed to lock '%s' (%m)."),
2f74e09
+				port->settings.usbscsi.path);
2f74e09
+			return GP_ERROR_IO;
2f74e09
 		}
2f74e09
-		return GP_ERROR_IO_LOCK;
2f74e09
 	}
2f74e09
-#else
2f74e09
-# ifdef __GCC__
2f74e09
-#  warning No locking library found. 
2f74e09
-#  warning You will run into problems if you use
2f74e09
-#  warning gphoto2 with a usbscsi picframe in 
2f74e09
-#  warning combination with Konqueror (KDE) or Nautilus (GNOME).
2f74e09
-#  warning This will *not* concern USB cameras.
2f74e09
-# endif
2f74e09
-#endif
2f74e09
 
2f74e09
 	return GP_OK;
2f74e09
 }
2f74e09
 
2f74e09
 static int
2f74e09
-gp_port_usbscsi_unlock (GPPort *port, const char *path)
2f74e09
+gp_port_usbscsi_unlock (GPPort *port)
2f74e09
 {
2f74e09
-#ifdef HAVE_LOCKDEV
2f74e09
-	int pid;
2f74e09
-
2f74e09
-	pid = dev_unlock (path, 0);
2f74e09
-	if (pid) {
2f74e09
-		if (port) {
2f74e09
-			if (pid > 0)
2f74e09
-				gp_port_set_error (port, _("Device '%s' could "
2f74e09
-					"not be unlocked as it is locked by "
2f74e09
-					"pid %d."), path, pid);
2f74e09
-			else
2f74e09
-				gp_port_set_error (port, _("Device '%s' could "
2f74e09
-					"not be unlocked (dev_unlock "
2f74e09
-					"returned %d)"), path, pid);
2f74e09
-		}
2f74e09
-		return GP_ERROR_IO_LOCK;
2f74e09
+	if (flock(port->pl->fd, LOCK_UN) != 0) {
2f74e09
+		gp_port_set_error (port, _("Failed to unlock '%s' (%m)."),
2f74e09
+				   port->settings.usbscsi.path);
2f74e09
+		return GP_ERROR_IO;
2f74e09
 	}
2f74e09
-#endif /* !HAVE_LOCKDEV */
2f74e09
-
2f74e09
 	return GP_OK;
2f74e09
 }
2f74e09
 
2f74e09
@@ -271,34 +245,36 @@
2f74e09
 	const int max_tries = 5;
2f74e09
 	const char *path = port->settings.usbscsi.path;
2f74e09
 
2f74e09
-	result = gp_port_usbscsi_lock (port, path);
2f74e09
-	if (result != GP_OK) {
2f74e09
-		for (i = 0; i < max_tries; i++) {
2f74e09
-			result = gp_port_usbscsi_lock (port, path);
2f74e09
-			if (result == GP_OK)
2f74e09
-				break;
2f74e09
-			gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
2f74e09
-				"Failed to get a lock, trying again...");
2f74e09
-			sleep (1);
2f74e09
-		}
2f74e09
-		CHECK (result)
2f74e09
-	}
2f74e09
 	port->pl->fd = open (path, O_RDWR);
2f74e09
 	if (port->pl->fd == -1) {
2f74e09
-		gp_port_usbscsi_unlock (port, path);
2f74e09
 		gp_port_set_error (port, _("Failed to open '%s' (%m)."), path);
2f74e09
 		return GP_ERROR_IO;
2f74e09
 	}
2f74e09
 
2f74e09
-	return GP_OK;
2f74e09
+	result = gp_port_usbscsi_lock (port);
2f74e09
+	for (i = 0; i < max_tries && result == GP_ERROR_IO_LOCK; i++) {
2f74e09
+		gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
2f74e09
+			"Failed to get a lock, trying again...");
2f74e09
+		sleep (1);
2f74e09
+		result = gp_port_usbscsi_lock (port);
2f74e09
+	}
2f74e09
+	if (result != GP_OK) {
2f74e09
+		close (port->pl->fd);
2f74e09
+		port->pl->fd = -1;
2f74e09
+	}
2f74e09
+	return result;
2f74e09
 }
2f74e09
 
2f74e09
 static int
2f74e09
 gp_port_usbscsi_close (GPPort *port)
2f74e09
 {
2f74e09
+	int result;
2f74e09
+
2f74e09
 	if (!port || port->pl->fd == -1)
2f74e09
 		return GP_OK;
2f74e09
 
2f74e09
+	result = gp_port_usbscsi_unlock (port);
2f74e09
+
2f74e09
 	if (close (port->pl->fd) == -1) {
2f74e09
 		gp_port_set_error (port, _("Could not close "
2f74e09
 			"'%s' (%m)."), port->settings.usbscsi.path);
2f74e09
@@ -306,10 +282,7 @@
2f74e09
 	}
2f74e09
 	port->pl->fd = -1;
2f74e09
 
2f74e09
-	CHECK (gp_port_usbscsi_unlock (port,
2f74e09
-					port->settings.usbscsi.path))
2f74e09
-
2f74e09
-	return GP_OK;
2f74e09
+	return result;
2f74e09
 }
2f74e09
 
2f74e09
 static int gp_port_usbscsi_send_scsi_cmd (GPPort *port, int to_dev, char *cmd,