~ubuntu-branches/ubuntu/saucy/libgphoto2/saucy-proposed

« back to all changes in this revision

Viewing changes to libgphoto2_port/usbscsi/linux.c

  • Committer: Package Import Robot
  • Author(s): Martin Pitt
  • Date: 2013-07-31 07:00:09 UTC
  • mfrom: (1.4.4)
  • Revision ID: package-import@ubuntu.com-20130731070009-enrbvg3hry64cxl1
Tags: 2.5.2-0ubuntu1
* New upstream release.
* Drop 01-increase_max_entries.patch, 02-libusbx_no_debug.patch,
  03-libusbx-fixes.patch: fixed upstream.
* Add libxml2-dev build dependency for new optional features.
* ABI changes: libgphoto2-2 → libgphoto2-6,
  libgphoto2-port0 → libgphoto2-port10
* debian/libgphoto2-dev-doc.install: Adjust to changed HTML API doc folder
  name.
* debian/libgphoto2-port10.install: Adjust for changed libgphoto-port ABI.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* SCSI commands to USB Mass storage devices port library for Linux
2
2
 * 
3
 
 *   Copyright (c) 2010 Hans de Goede <hdegoede@redhat.com>
 
3
 *   Copyright (c) 2010-2012 Hans de Goede <hdegoede@redhat.com>
4
4
 *
5
5
 * This program is free software; you can redistribute it and/or modify
6
6
 * it under the terms of the GNU Lesser General Public License as published by
16
16
 * along with this program; if not, write to the Free Software
17
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
18
 */
 
19
 
 
20
#define _BSD_SOURCE     /* for flock */
 
21
 
19
22
#include "config.h"
20
23
#include <gphoto2/gphoto2-port-library.h>
21
24
 
 
25
#include <errno.h>
22
26
#include <stdio.h>
23
27
#include <stdlib.h>
24
28
#include <unistd.h>
29
33
#ifdef HAVE_LIMITS_H
30
34
# include <limits.h>
31
35
#endif
 
36
#ifdef HAVE_SYS_FILE_H
 
37
# include <sys/file.h>
 
38
#endif
32
39
#include <sys/stat.h>
33
40
#include <sys/types.h>
34
41
#ifdef HAVE_SYS_PARAM_H
40
47
#ifdef HAVE_SCSI_SG_H
41
48
# include <scsi/sg.h>
42
49
#endif
43
 
#ifdef HAVE_LOCKDEV
44
 
#  include <lockdev.h>
45
 
#endif
46
50
 
47
51
#include <gphoto2/gphoto2-port-result.h>
48
52
#include <gphoto2/gphoto2-port-log.h>
80
84
}
81
85
 
82
86
static int
83
 
gp_port_usbscsi_lock (GPPort *port, const char *path)
 
87
gp_port_usbscsi_lock (GPPort *port)
84
88
{
85
 
#ifdef HAVE_LOCKDEV
86
 
        int pid;
87
 
 
 
89
#if HAVE_FLOCK
88
90
        gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
89
 
                "Trying to lock '%s'...", path);
 
91
                "Trying to lock '%s'...", port->settings.usbscsi.path);
90
92
 
91
 
        pid = dev_lock (path);
92
 
        if (pid) {
93
 
                if (port) {
94
 
                        if (pid > 0)
95
 
                                gp_port_set_error (port, _("Device '%s' is "
96
 
                                        "locked by pid %d"), path, pid);
97
 
                        else
98
 
                                gp_port_set_error (port, _("Device '%s' could "
99
 
                                        "not be locked (dev_lock returned "
100
 
                                        "%d)"), path, pid);
 
93
        if (flock(port->pl->fd, LOCK_EX | LOCK_NB) != 0) {
 
94
                switch (errno) {
 
95
                case EWOULDBLOCK:
 
96
                        gp_port_set_error (port,
 
97
                                _("Device '%s' is locked by another app."),
 
98
                                port->settings.usbscsi.path);
 
99
                        return GP_ERROR_IO_LOCK;
 
100
                default:
 
101
                        gp_port_set_error (port,
 
102
                                _("Failed to lock '%s' (%m)."),
 
103
                                port->settings.usbscsi.path);
 
104
                        return GP_ERROR_IO;
101
105
                }
102
 
                return GP_ERROR_IO_LOCK;
103
106
        }
104
107
#else
105
 
# ifdef __GCC__
106
 
#  warning No locking library found. 
107
 
#  warning You will run into problems if you use
108
 
#  warning gphoto2 with a usbscsi picframe in 
109
 
#  warning combination with Konqueror (KDE) or Nautilus (GNOME).
110
 
#  warning This will *not* concern USB cameras.
111
 
# endif
 
108
        gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
 
109
                "Locking '%s' not possible, flock not availbale.", port->settings.usbscsi.path);
112
110
#endif
113
 
 
114
111
        return GP_OK;
115
112
}
116
113
 
117
114
static int
118
 
gp_port_usbscsi_unlock (GPPort *port, const char *path)
 
115
gp_port_usbscsi_unlock (GPPort *port)
119
116
{
120
 
#ifdef HAVE_LOCKDEV
121
 
        int pid;
122
 
 
123
 
        pid = dev_unlock (path, 0);
124
 
        if (pid) {
125
 
                if (port) {
126
 
                        if (pid > 0)
127
 
                                gp_port_set_error (port, _("Device '%s' could "
128
 
                                        "not be unlocked as it is locked by "
129
 
                                        "pid %d."), path, pid);
130
 
                        else
131
 
                                gp_port_set_error (port, _("Device '%s' could "
132
 
                                        "not be unlocked (dev_unlock "
133
 
                                        "returned %d)"), path, pid);
134
 
                }
135
 
                return GP_ERROR_IO_LOCK;
 
117
#ifdef HAVE_FLOCK
 
118
        if (flock(port->pl->fd, LOCK_UN) != 0) {
 
119
                gp_port_set_error (port, _("Failed to unlock '%s' (%m)."),
 
120
                                   port->settings.usbscsi.path);
 
121
                return GP_ERROR_IO;
136
122
        }
137
 
#endif /* !HAVE_LOCKDEV */
138
 
 
 
123
#endif
139
124
        return GP_OK;
140
125
}
141
126
 
220
205
                return GP_OK;
221
206
 
222
207
        while ((dirent = readdir (dir))) {
 
208
                char path[4096];
223
209
                if (gp_port_usbscsi_get_usb_id (dirent->d_name,
224
210
                                &vendor_id, &product_id) != GP_OK)
225
211
                        continue; /* Not a usb device */
226
212
 
227
 
                info.type = GP_PORT_USB_SCSI;
228
 
                snprintf (info.path, sizeof (info.path),
 
213
                gp_port_info_new (&info);
 
214
                gp_port_info_set_type (info, GP_PORT_USB_SCSI);
 
215
                snprintf (path, sizeof (path),
229
216
                          "usbscsi:/dev/%s",
230
217
                          dirent->d_name);
231
 
                snprintf (info.name, sizeof (info.name),
232
 
                          _("USB Mass Storage raw SCSI"));
 
218
                gp_port_info_set_path (info, path);
 
219
                gp_port_info_set_name (info, _("USB Mass Storage raw SCSI"));
233
220
                CHECK (gp_port_info_list_append (list, info))
234
221
        }
235
222
        closedir (dir);
269
256
        const int max_tries = 5;
270
257
        const char *path = port->settings.usbscsi.path;
271
258
 
272
 
        result = gp_port_usbscsi_lock (port, path);
273
 
        if (result != GP_OK) {
274
 
                for (i = 0; i < max_tries; i++) {
275
 
                        result = gp_port_usbscsi_lock (port, path);
276
 
                        if (result == GP_OK)
277
 
                                break;
278
 
                        gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
279
 
                                "Failed to get a lock, trying again...");
280
 
                        sleep (1);
281
 
                }
282
 
                CHECK (result)
283
 
        }
284
259
        port->pl->fd = open (path, O_RDWR);
285
260
        if (port->pl->fd == -1) {
286
 
                gp_port_usbscsi_unlock (port, path);
287
261
                gp_port_set_error (port, _("Failed to open '%s' (%m)."), path);
288
262
                return GP_ERROR_IO;
289
263
        }
290
264
 
291
 
        return GP_OK;
 
265
        result = gp_port_usbscsi_lock (port);
 
266
        for (i = 0; i < max_tries && result == GP_ERROR_IO_LOCK; i++) {
 
267
                gp_log (GP_LOG_DEBUG, "gphoto2-port-usbscsi",
 
268
                        "Failed to get a lock, trying again...");
 
269
                sleep (1);
 
270
                result = gp_port_usbscsi_lock (port);
 
271
        }
 
272
        if (result != GP_OK) {
 
273
                close (port->pl->fd);
 
274
                port->pl->fd = -1;
 
275
        }
 
276
        return result;
292
277
}
293
278
 
294
279
static int
295
280
gp_port_usbscsi_close (GPPort *port)
296
281
{
 
282
        int result;
 
283
 
297
284
        if (!port || port->pl->fd == -1)
298
285
                return GP_OK;
299
286
 
 
287
        result = gp_port_usbscsi_unlock (port);
 
288
 
300
289
        if (close (port->pl->fd) == -1) {
301
290
                gp_port_set_error (port, _("Could not close "
302
291
                        "'%s' (%m)."), port->settings.usbscsi.path);
304
293
        }
305
294
        port->pl->fd = -1;
306
295
 
307
 
        CHECK (gp_port_usbscsi_unlock (port,
308
 
                                        port->settings.usbscsi.path))
309
 
 
310
 
        return GP_OK;
 
296
        return result;
311
297
}
312
298
 
313
299
static int gp_port_usbscsi_send_scsi_cmd (GPPort *port, int to_dev, char *cmd,
338
324
        io_hdr.mx_sb_len = sense_size;
339
325
        io_hdr.dxferp = (unsigned char *)data;
340
326
        io_hdr.dxfer_len = data_size;
341
 
        io_hdr.timeout = 500;
 
327
        /*io_hdr.timeout = 1500;*/
 
328
        io_hdr.timeout = port->timeout;
 
329
        gp_log (GP_LOG_DEBUG, "port/usbscsi", "setting scsi command timeout to %d", port->timeout);
 
330
        if (io_hdr.timeout < 1500)
 
331
                io_hdr.timeout = 1500;
342
332
 
343
333
        if (ioctl (port->pl->fd, SG_IO, &io_hdr) < 0)
344
334
        {
346
336
                        "'%s' (%m)."), port->settings.usbscsi.path);
347
337
                return GP_ERROR_IO;
348
338
        }
349
 
        /* https://secure.wikimedia.org/wikipedia/en/wiki/Key_Code_Qualifier */
350
 
        if (sense[0] != 0) {
351
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","Request Sense reports:");
352
 
                if ((sense[0]&0x7f)!=0x70) {
353
 
                        gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tInvalid header.");
354
 
                        return GP_ERROR_IO;
355
 
                }
356
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tCurrent command read filemark: %s",(sense[2]&0x80)?"yes":"no");
357
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tEarly warning passed: %s",(sense[2]&0x40)?"yes":"no");
358
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tIncorrect blocklengt: %s",(sense[2]&0x20)?"yes":"no");
359
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tSense Key: %d",sense[2]&0xf);
360
 
                if (sense[0]&0x80)
361
 
                        gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tResidual Length: %d",sense[3]*0x1000000+sense[4]*0x10000+sense[5]*0x100+sense[6]);
362
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tAdditional Sense Length: %d",sense[7]);
363
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tAdditional Sense Code: %d",sense[12]);
364
 
                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tAdditional Sense Code Qualifier: %d",sense[13]);
365
 
                if (sense[15]&0x80) {
366
 
                        gp_log(GP_LOG_DEBUG,"send_scsi_cmd","\tIllegal Param is in %s",(sense[15]&0x40)?"the CDB":"the Data Out Phase");
367
 
                        if (sense[15]&0x8) {
368
 
                                gp_log(GP_LOG_DEBUG,"send_scsi_cmd","Pointer at %d, bit %d",sense[16]*256+sense[17],sense[15]&0x7);
369
 
                        }
370
 
                }
371
 
        }
372
339
        return GP_OK;
373
340
#else
374
341
        return GP_ERROR_NOT_SUPPORTED;