oops, need this patch file too
[debian/amanda] / device-src / tape-device.c
1 /*
2  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of the GNU General Public License version 2 as published
6  * by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
11  * for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16  *
17  * Contact information: Zmanda Inc., 465 S. Mathilda Ave., Suite 300
18  * Sunnyvale, CA 94085, USA, or: http://www.zmanda.com
19  */
20
21 #include "amanda.h"
22 #include "pipespawn.h"
23 #include <string.h> /* memset() */
24 #include "util.h"
25 #include "device.h"
26
27 #ifdef HAVE_SYS_TAPE_H
28 # include <sys/tape.h>
29 #endif
30 #ifdef HAVE_SYS_MTIO_H
31 # include <sys/mtio.h>
32 #endif
33 #ifdef HAVE_LIMITS_H
34 # include <limits.h>
35 #endif
36
37 /* This is equal to 2*1024*1024*1024 - 16*1024*1024 - 1, but written
38    explicitly to avoid overflow issues. */
39 #define RESETOFS_THRESHOLD (0x7effffff)
40
41 /* Largest possible block size on SCSI systems. */
42 #define LARGEST_BLOCK_ESTIMATE (16 * 1024 * 1024)
43
44 /*
45  * Type checking and casting macros
46  */
47
48 #define TYPE_TAPE_DEVICE        (tape_device_get_type())
49 #define TAPE_DEVICE(obj)        G_TYPE_CHECK_INSTANCE_CAST((obj), tape_device_get_type(), TapeDevice)
50 #define TAPE_DEVICE_CONST(obj)  G_TYPE_CHECK_INSTANCE_CAST((obj), tape_device_get_type(), TapeDevice const)
51 #define TAPE_DEVICE_CLASS(klass)        G_TYPE_CHECK_CLASS_CAST((klass), tape_device_get_type(), TapeDeviceClass)
52 #define IS_TAPE_DEVICE(obj)     G_TYPE_CHECK_INSTANCE_TYPE((obj), tape_device_get_type ())
53 #define TAPE_DEVICE_GET_CLASS(obj)      G_TYPE_INSTANCE_GET_CLASS((obj), tape_device_get_type(), TapeDeviceClass)
54 GType   tape_device_get_type    (void);
55
56 /*
57  * Main object structure
58  */
59 typedef struct TapeDevicePrivate_s TapeDevicePrivate;
60 typedef struct _TapeDevice {
61     Device __parent__;
62
63     /* It should go without saying that all this stuff is
64      * look-but-don't-touch. */
65
66     /* characteristics of the device */
67     gboolean fsf, bsf, fsr, bsr, eom, bsf_after_eom, broken_gmt_online;
68     gboolean leom;
69     gboolean nonblocking_open, fsf_after_filemark;
70     int final_filemarks;
71
72     /* 0 if we opened with O_RDWR; error otherwise. */
73     gboolean write_open_errno;
74     int fd;
75
76     TapeDevicePrivate * private;
77 } TapeDevice;
78
79 struct TapeDevicePrivate_s {
80     /* This holds the total number of bytes written to the device,
81        modulus RESETOFS_THRESHOLD. */
82     int write_count;
83     char * device_filename;
84     gsize read_block_size;
85 };
86
87 /*
88  * Class definition
89  */
90
91 typedef struct _TapeDeviceClass TapeDeviceClass;
92 struct _TapeDeviceClass {
93         DeviceClass __parent__;
94 };
95
96 void tape_device_register(void);
97
98 /* useful callback for tape ops */
99 void tape_device_set_capabilities(TapeDevice *self,
100         gboolean fsf, PropertySurety fsf_surety, PropertySource fsf_source,
101         gboolean fsf_after_filemark, PropertySurety faf_surety, PropertySource faf_source,
102         gboolean bsf, PropertySurety bsf_surety, PropertySource bsf_source,
103         gboolean fsr, PropertySurety fsr_surety, PropertySource fsr_source,
104         gboolean bsr, PropertySurety bsr_surety, PropertySource bsr_source,
105         gboolean eom, PropertySurety eom_surety, PropertySource eom_source,
106         gboolean leom, PropertySurety leom_surety, PropertySource leom_source,
107         gboolean bsf_after_eom, PropertySurety bae_surety, PropertySource bae_source,
108         guint final_filemarks, PropertySurety ff_surety, PropertySource ff_source);
109
110 /* Real Operations (always return FALSE if not implemented) */
111 gboolean tape_rewind(int fd);
112 gboolean tape_fsf(int fd, guint count);
113 gboolean tape_bsf(int fd, guint count);
114 gboolean tape_fsr(int fd, guint count);
115 gboolean tape_bsr(int fd, guint count);
116 gint tape_fileno(int fd);
117
118 /* tape_fileno returns tape position file number, or one of these: */
119 #define TAPE_OP_ERROR -1
120 #define TAPE_POSITION_UNKNOWN -2
121
122 /* Possible (abstracted) results from a system I/O operation. */
123 typedef enum {
124     RESULT_SUCCESS,
125     RESULT_ERROR,        /* Undefined error (*errmsg set) */
126     RESULT_SMALL_BUFFER, /* Tried to read with a buffer that is too
127                             small. */
128     RESULT_NO_DATA,      /* End of File, while reading */
129     RESULT_NO_SPACE,     /* Out of space. Sometimes we don't know if
130                             it was this or I/O error, but this is the
131                             preferred explanation. */
132     RESULT_MAX
133 } IoResult;
134
135 /* returns a fileno like tape_fileno */
136 gint tape_eod(int fd);
137
138 gboolean tape_weof(int fd, guint8 count);
139 gboolean tape_setcompression(int fd, gboolean on);
140
141 gboolean tape_offl(int fd);
142
143 DeviceStatusFlags tape_is_tape_device(int fd);
144 DeviceStatusFlags tape_is_ready(int fd, TapeDevice *t_self);
145
146 #define tape_device_read_size(self) \
147     (((TapeDevice *)(self))->private->read_block_size? \
148         ((TapeDevice *)(self))->private->read_block_size : ((Device *)(self))->block_size)
149
150 /*
151  * Our device-specific properties.
152  */
153
154 #define PROPERTY_BROKEN_GMT_ONLINE (device_property_broken_gmt_online.ID)
155 #define PROPERTY_FSF (device_property_fsf.ID)
156 #define PROPERTY_FSF_AFTER_FILEMARK (device_property_fsf_after_filemark.ID)
157 #define PROPERTY_BSF (device_property_bsf.ID)
158 #define PROPERTY_FSR (device_property_fsr.ID)
159 #define PROPERTY_BSR (device_property_bsr.ID)
160 #define PROPERTY_EOM (device_property_eom.ID)
161 #define PROPERTY_BSF_AFTER_EOM (device_property_bsf_after_eom.ID)
162 #define PROPERTY_NONBLOCKING_OPEN (device_property_nonblocking_open.ID)
163 #define PROPERTY_FINAL_FILEMARKS (device_property_final_filemarks.ID)
164
165 static DevicePropertyBase device_property_broken_gmt_online;
166 static DevicePropertyBase device_property_fsf;
167 static DevicePropertyBase device_property_fsf_after_filemark;
168 static DevicePropertyBase device_property_bsf;
169 static DevicePropertyBase device_property_fsr;
170 static DevicePropertyBase device_property_bsr;
171 static DevicePropertyBase device_property_eom;
172 static DevicePropertyBase device_property_bsf_after_eom;
173 static DevicePropertyBase device_property_nonblocking_open;
174 static DevicePropertyBase device_property_final_filemarks;
175 static DevicePropertyBase device_property_read_buffer_size; /* old name for READ_BLOCK_SIZE */
176
177 /* here are local prototypes */
178 static void tape_device_init (TapeDevice * o);
179 static void tape_device_class_init (TapeDeviceClass * c);
180 static void tape_device_base_init (TapeDeviceClass * c);
181 static gboolean tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
182                                     GValue *val, PropertySurety surety, PropertySource source);
183 static gboolean tape_device_set_final_filemarks_fn(Device *p_self, DevicePropertyBase *base,
184                                     GValue *val, PropertySurety surety, PropertySource source);
185 static gboolean tape_device_set_compression_fn(Device *p_self, DevicePropertyBase *base,
186                                     GValue *val, PropertySurety surety, PropertySource source);
187 static gboolean tape_device_get_read_block_size_fn(Device *p_self, DevicePropertyBase *base,
188                                     GValue *val, PropertySurety *surety, PropertySource *source);
189 static gboolean tape_device_set_read_block_size_fn(Device *p_self, DevicePropertyBase *base,
190                                     GValue *val, PropertySurety surety, PropertySource source);
191 static void tape_device_open_device (Device * self, char * device_name, char * device_type, char * device_node);
192 static Device * tape_device_factory (char * device_name, char * device_type, char * device_node);
193 static DeviceStatusFlags tape_device_read_label(Device * self);
194 static gboolean tape_device_write_block(Device * self, guint size, gpointer data);
195 static int tape_device_read_block(Device * self,  gpointer buf,
196                                        int * size_req);
197 static gboolean tape_device_start (Device * self, DeviceAccessMode mode,
198                                    char * label, char * timestamp);
199 static gboolean tape_device_start_file (Device * self, dumpfile_t * ji);
200 static gboolean tape_device_finish_file (Device * self);
201 static dumpfile_t * tape_device_seek_file (Device * self, guint file);
202 static gboolean tape_device_seek_block (Device * self, guint64 block);
203 static gboolean tape_device_eject (Device * self);
204 static gboolean tape_device_finish (Device * self);
205 static IoResult tape_device_robust_read (TapeDevice * self, void * buf,
206                                                int * count, char **errmsg);
207 static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count, char **errmsg);
208 static gboolean tape_device_fsf (TapeDevice * self, guint count);
209 static gboolean tape_device_fsr (TapeDevice * self, guint count);
210 static gboolean tape_device_bsr (TapeDevice * self, guint count, guint file, guint block);
211 static gboolean tape_device_eod (TapeDevice * self);
212
213 /* pointer to the class of our parent */
214 static DeviceClass *parent_class = NULL;
215
216 GType tape_device_get_type (void)
217 {
218     static GType type = 0;
219
220     if G_UNLIKELY(type == 0) {
221         static const GTypeInfo info = {
222             sizeof (TapeDeviceClass),
223             (GBaseInitFunc) tape_device_base_init,
224             (GBaseFinalizeFunc) NULL,
225             (GClassInitFunc) tape_device_class_init,
226             (GClassFinalizeFunc) NULL,
227             NULL /* class_data */,
228             sizeof (TapeDevice),
229             0 /* n_preallocs */,
230             (GInstanceInitFunc) tape_device_init,
231             NULL
232         };
233
234         type = g_type_register_static (TYPE_DEVICE, "TapeDevice",
235                                        &info, (GTypeFlags)0);
236     }
237
238     return type;
239 }
240
241 static void
242 tape_device_init (TapeDevice * self) {
243     Device * d_self;
244     GValue response;
245
246     d_self = DEVICE(self);
247     bzero(&response, sizeof(response));
248
249     self->private = g_new0(TapeDevicePrivate, 1);
250
251     /* Clear all fields. */
252     d_self->block_size = 32768;
253     d_self->min_block_size = 32768;
254     d_self->max_block_size = LARGEST_BLOCK_ESTIMATE;
255     self->broken_gmt_online = FALSE;
256
257     self->fd = -1;
258
259     /* set all of the feature properties to an unsure default of FALSE */
260     self->broken_gmt_online = FALSE;
261     self->fsf = FALSE;
262     self->bsf = FALSE;
263     self->fsr = FALSE;
264     self->bsr = FALSE;
265     self->eom = FALSE;
266     self->leom = FALSE;
267     self->bsf_after_eom = FALSE;
268
269     g_value_init(&response, G_TYPE_BOOLEAN);
270     g_value_set_boolean(&response, FALSE);
271     device_set_simple_property(d_self, PROPERTY_BROKEN_GMT_ONLINE,
272             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
273     device_set_simple_property(d_self, PROPERTY_FSF,
274             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
275     device_set_simple_property(d_self, PROPERTY_FSF_AFTER_FILEMARK,
276             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
277     device_set_simple_property(d_self, PROPERTY_BSF,
278             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
279     device_set_simple_property(d_self, PROPERTY_FSR,
280             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
281     device_set_simple_property(d_self, PROPERTY_BSR,
282             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
283     device_set_simple_property(d_self, PROPERTY_EOM,
284             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
285     device_set_simple_property(d_self, PROPERTY_LEOM,
286             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
287     device_set_simple_property(d_self, PROPERTY_BSF_AFTER_EOM,
288             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
289
290 #ifdef DEFAULT_TAPE_NON_BLOCKING_OPEN
291     self->nonblocking_open = TRUE;
292 #else
293     self->nonblocking_open = FALSE;
294 #endif
295     g_value_set_boolean(&response, self->nonblocking_open);
296     device_set_simple_property(d_self, PROPERTY_NONBLOCKING_OPEN,
297             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
298     g_value_unset(&response);
299
300     self->final_filemarks = 2;
301     g_value_init(&response, G_TYPE_UINT);
302     g_value_set_uint(&response, self->final_filemarks);
303     device_set_simple_property(d_self, PROPERTY_FINAL_FILEMARKS,
304             &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
305     g_value_unset(&response);
306
307     self->private->read_block_size = 0;
308     g_value_init(&response, G_TYPE_UINT);
309     g_value_set_uint(&response, self->private->read_block_size);
310     device_set_simple_property(d_self, PROPERTY_READ_BLOCK_SIZE,
311             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DEFAULT);
312     g_value_unset(&response);
313
314     self->private->write_count = 0;
315     self->private->device_filename = NULL;
316
317     /* Static properites */
318     g_value_init(&response, CONCURRENCY_PARADIGM_TYPE);
319     g_value_set_enum(&response, CONCURRENCY_PARADIGM_EXCLUSIVE);
320     device_set_simple_property(d_self, PROPERTY_CONCURRENCY,
321             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
322     g_value_unset(&response);
323
324     g_value_init(&response, STREAMING_REQUIREMENT_TYPE);
325     g_value_set_enum(&response, STREAMING_REQUIREMENT_DESIRED);
326     device_set_simple_property(d_self, PROPERTY_STREAMING,
327             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
328     g_value_unset(&response);
329
330     g_value_init(&response, G_TYPE_BOOLEAN);
331     g_value_set_boolean(&response, TRUE);
332     device_set_simple_property(d_self, PROPERTY_APPENDABLE,
333             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
334     g_value_unset(&response);
335
336     g_value_init(&response, G_TYPE_BOOLEAN);
337     g_value_set_boolean(&response, FALSE);
338     device_set_simple_property(d_self, PROPERTY_PARTIAL_DELETION,
339             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
340     g_value_unset(&response);
341
342     g_value_init(&response, G_TYPE_BOOLEAN);
343     g_value_set_boolean(&response, FALSE);
344     device_set_simple_property(d_self, PROPERTY_FULL_DELETION,
345             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
346     g_value_unset(&response);
347
348     g_value_init(&response, MEDIA_ACCESS_MODE_TYPE);
349     g_value_set_enum(&response, MEDIA_ACCESS_MODE_READ_WRITE);
350     device_set_simple_property(d_self, PROPERTY_MEDIUM_ACCESS_TYPE,
351             &response, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
352     g_value_unset(&response);
353 }
354
355 static void tape_device_finalize(GObject * obj_self) {
356     TapeDevice * self = TAPE_DEVICE(obj_self);
357
358     if(G_OBJECT_CLASS(parent_class)->finalize) \
359            (* G_OBJECT_CLASS(parent_class)->finalize)(obj_self);
360
361     robust_close(self->fd);
362     self->fd = -1;
363     amfree(self->private->device_filename);
364     amfree(self->private);
365 }
366
367 static void
368 tape_device_class_init (TapeDeviceClass * c)
369 {
370     DeviceClass *device_class = (DeviceClass *)c;
371     GObjectClass *g_object_class = (GObjectClass *)c;
372
373     parent_class = g_type_class_ref (TYPE_DEVICE);
374
375     device_class->open_device = tape_device_open_device;
376     device_class->read_label = tape_device_read_label;
377     device_class->write_block = tape_device_write_block;
378     device_class->read_block = tape_device_read_block;
379     device_class->start = tape_device_start;
380     device_class->start_file = tape_device_start_file;
381     device_class->finish_file = tape_device_finish_file;
382     device_class->seek_file = tape_device_seek_file;
383     device_class->seek_block = tape_device_seek_block;
384     device_class->eject = tape_device_eject;
385     device_class->finish = tape_device_finish;
386
387     g_object_class->finalize = tape_device_finalize;
388 }
389
390 static void
391 tape_device_base_init (TapeDeviceClass * c)
392 {
393     DeviceClass *device_class = (DeviceClass *)c;
394
395     device_class_register_property(device_class, PROPERTY_BROKEN_GMT_ONLINE,
396             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
397             device_simple_property_get_fn,
398             tape_device_set_feature_property_fn);
399
400     device_class_register_property(device_class, PROPERTY_FSF,
401             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
402             device_simple_property_get_fn,
403             tape_device_set_feature_property_fn);
404
405     device_class_register_property(device_class, PROPERTY_FSF_AFTER_FILEMARK,
406             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
407             device_simple_property_get_fn,
408             tape_device_set_feature_property_fn);
409
410     device_class_register_property(device_class, PROPERTY_BSF,
411             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
412             device_simple_property_get_fn,
413             tape_device_set_feature_property_fn);
414
415     device_class_register_property(device_class, PROPERTY_FSR,
416             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
417             device_simple_property_get_fn,
418             tape_device_set_feature_property_fn);
419
420     device_class_register_property(device_class, PROPERTY_BSR,
421             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
422             device_simple_property_get_fn,
423             tape_device_set_feature_property_fn);
424
425     device_class_register_property(device_class, PROPERTY_EOM,
426             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
427             device_simple_property_get_fn,
428             tape_device_set_feature_property_fn);
429
430     device_class_register_property(device_class, PROPERTY_BSF_AFTER_EOM,
431             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
432             device_simple_property_get_fn,
433             tape_device_set_feature_property_fn);
434
435     device_class_register_property(device_class, PROPERTY_NONBLOCKING_OPEN,
436             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
437             device_simple_property_get_fn,
438             tape_device_set_feature_property_fn);
439
440     device_class_register_property(device_class, PROPERTY_FINAL_FILEMARKS,
441             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
442             device_simple_property_get_fn,
443             tape_device_set_final_filemarks_fn);
444
445     /* We don't (yet?) support reading the device's compression state, so not
446      * gettable. */
447     device_class_register_property(device_class, PROPERTY_COMPRESSION,
448             PROPERTY_ACCESS_SET_MASK,
449             NULL,
450             tape_device_set_compression_fn);
451
452     device_class_register_property(device_class, PROPERTY_READ_BLOCK_SIZE,
453             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
454             tape_device_get_read_block_size_fn,
455             tape_device_set_read_block_size_fn);
456
457     device_class_register_property(device_class, device_property_read_buffer_size.ID,
458             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
459             tape_device_get_read_block_size_fn,
460             tape_device_set_read_block_size_fn);
461
462     /* add the ability to set LEOM to FALSE, for testing purposes */
463     device_class_register_property(device_class, PROPERTY_LEOM,
464             PROPERTY_ACCESS_GET_MASK | PROPERTY_ACCESS_SET_BEFORE_START,
465             device_simple_property_get_fn,
466             tape_device_set_feature_property_fn);
467 }
468
469 static gboolean
470 tape_device_set_feature_property_fn(Device *p_self, DevicePropertyBase *base,
471     GValue *val, PropertySurety surety, PropertySource source)
472 {
473     TapeDevice *self = TAPE_DEVICE(p_self);
474     GValue old_val;
475     gboolean old_bool, new_bool;
476     PropertySurety old_surety;
477     PropertySource old_source;
478
479     new_bool = g_value_get_boolean(val);
480
481     /* get the old source and surety and see if we're willing to make this change */
482     bzero(&old_val, sizeof(old_val));
483     if (device_get_simple_property(p_self, base->ID, &old_val, &old_surety, &old_source)) {
484         old_bool = g_value_get_boolean(&old_val);
485
486         if (old_surety == PROPERTY_SURETY_GOOD && old_source == PROPERTY_SOURCE_DETECTED) {
487             if (new_bool != old_bool) {
488                 device_set_error(p_self, vstrallocf(_(
489                            "Value for property '%s' was autodetected and cannot be changed"),
490                            base->name),
491                     DEVICE_STATUS_DEVICE_ERROR);
492                 return FALSE;
493             } else {
494                 /* pretend we set it, but don't change surety/source */
495                 return TRUE;
496             }
497         }
498     }
499
500     /* (note: PROPERTY_* are not constants, so we can't use switch) */
501     if (base->ID == PROPERTY_BROKEN_GMT_ONLINE)
502         self->broken_gmt_online = new_bool;
503     else if (base->ID == PROPERTY_FSF)
504         self->fsf = new_bool;
505     else if (base->ID == PROPERTY_FSF_AFTER_FILEMARK)
506         self->fsf_after_filemark = new_bool;
507     else if (base->ID == PROPERTY_BSF)
508         self->bsf = new_bool;
509     else if (base->ID == PROPERTY_FSR)
510         self->fsr = new_bool;
511     else if (base->ID == PROPERTY_BSR)
512         self->bsr = new_bool;
513     else if (base->ID == PROPERTY_EOM)
514         self->eom = new_bool;
515     else if (base->ID == PROPERTY_BSF_AFTER_EOM)
516         self->bsf_after_eom = new_bool;
517     else if (base->ID == PROPERTY_NONBLOCKING_OPEN)
518         self->nonblocking_open = new_bool;
519     else if (base->ID == PROPERTY_LEOM)
520         self->leom = new_bool;
521     else
522         return FALSE; /* shouldn't happen */
523
524     return device_simple_property_set_fn(p_self, base, val, surety, source);
525 }
526
527 static gboolean
528 tape_device_set_final_filemarks_fn(Device *p_self, DevicePropertyBase *base,
529     GValue *val, PropertySurety surety, PropertySource source)
530 {
531     TapeDevice *self = TAPE_DEVICE(p_self);
532     GValue old_val;
533     gboolean old_int, new_int;
534     PropertySurety old_surety;
535     PropertySource old_source;
536
537     new_int = g_value_get_uint(val);
538
539     /* get the old source and surety and see if we're willing to make this change */
540     bzero(&old_val, sizeof(old_val));
541     if (device_get_simple_property(p_self, base->ID, &old_val, &old_surety, &old_source)) {
542         old_int = g_value_get_uint(&old_val);
543
544         if (old_surety == PROPERTY_SURETY_GOOD && old_source == PROPERTY_SOURCE_DETECTED) {
545             if (new_int != old_int) {
546                 device_set_error(p_self, vstrallocf(_(
547                            "Value for property '%s' was autodetected and cannot be changed"),
548                            base->name),
549                     DEVICE_STATUS_DEVICE_ERROR);
550                 return FALSE;
551             } else {
552                 /* pretend we set it, but don't change surety/source */
553                 return TRUE;
554             }
555         }
556     }
557
558     self->final_filemarks = new_int;
559
560     return device_simple_property_set_fn(p_self, base, val, surety, source);
561 }
562
563 static gboolean
564 tape_device_set_compression_fn(Device *p_self, DevicePropertyBase *base,
565     GValue *val, PropertySurety surety, PropertySource source)
566 {
567     TapeDevice *self = TAPE_DEVICE(p_self);
568     gboolean request = g_value_get_boolean(val);
569
570     /* We allow this property to be set at any time. This is mostly
571      * because setting compression is a hit-and-miss proposition
572      * at any time; some drives accept the mode setting but don't
573      * actually support compression, while others do support
574      * compression but do it via density settings or some other
575      * way. Set this property whenever you want, but all we'll do
576      * is report whether or not the ioctl succeeded. */
577     if (tape_setcompression(self->fd, request)) {
578         /* looks good .. let's start the device over, though */
579         device_clear_volume_details(p_self);
580     } else {
581         device_set_error(p_self,
582             g_strdup("Error setting COMPRESION property"),
583             DEVICE_STATUS_DEVICE_ERROR);
584         return FALSE;
585     }
586
587     return device_simple_property_set_fn(p_self, base, val, surety, source);
588 }
589
590 static gboolean
591 tape_device_get_read_block_size_fn(Device *p_self, DevicePropertyBase *base G_GNUC_UNUSED,
592     GValue *val, PropertySurety *surety, PropertySource *source)
593 {
594     /* use the READ_BLOCK_SIZE, even if we're invoked to get the old READ_BUFFER_SIZE */
595     return device_simple_property_get_fn(p_self, &device_property_read_block_size,
596                                         val, surety, source);
597 }
598
599 static gboolean
600 tape_device_set_read_block_size_fn(Device *p_self, DevicePropertyBase *base G_GNUC_UNUSED,
601     GValue *val, PropertySurety surety, PropertySource source)
602 {
603     TapeDevice *self = TAPE_DEVICE(p_self);
604     guint read_block_size = g_value_get_uint(val);
605
606     if (read_block_size != 0 &&
607             ((gsize)read_block_size < p_self->block_size ||
608              (gsize)read_block_size > p_self->max_block_size))
609         device_set_error(p_self,
610             g_strdup_printf("Error setting READ-BLOCk-SIZE property to '%u', it must be between %zu and %zu", read_block_size, p_self->block_size, p_self->max_block_size),
611             DEVICE_STATUS_DEVICE_ERROR);
612         return FALSE;
613
614     self->private->read_block_size = read_block_size;
615
616     /* use the READ_BLOCK_SIZE, even if we're invoked to get the old READ_BUFFER_SIZE */
617     return device_simple_property_set_fn(p_self, &device_property_read_block_size,
618                                         val, surety, source);
619 }
620
621 void tape_device_register(void) {
622     static const char * device_prefix_list[] = { "tape", NULL };
623
624     /* First register tape-specific properties */
625     device_property_fill_and_register(&device_property_broken_gmt_online,
626                                       G_TYPE_BOOLEAN, "broken_gmt_online",
627       "Does this drive support the GMT_ONLINE macro?");
628
629     device_property_fill_and_register(&device_property_fsf,
630                                       G_TYPE_BOOLEAN, "fsf",
631       "Does this drive support the MTFSF command?");
632
633     device_property_fill_and_register(&device_property_fsf_after_filemark,
634                                       G_TYPE_BOOLEAN, "fsf_after_filemark",
635       "Does this drive needs a FSF if a filemark is already read?");
636
637     device_property_fill_and_register(&device_property_bsf,
638                                       G_TYPE_BOOLEAN, "bsf",
639       "Does this drive support the MTBSF command?" );
640
641     device_property_fill_and_register(&device_property_fsr,
642                                       G_TYPE_BOOLEAN, "fsr",
643       "Does this drive support the MTFSR command?");
644
645     device_property_fill_and_register(&device_property_bsr,
646                                       G_TYPE_BOOLEAN, "bsr",
647       "Does this drive support the MTBSR command?");
648
649     device_property_fill_and_register(&device_property_eom,
650                                       G_TYPE_BOOLEAN, "eom",
651       "Does this drive support the MTEOM command?");
652
653     device_property_fill_and_register(&device_property_bsf_after_eom,
654                                       G_TYPE_BOOLEAN,
655                                       "bsf_after_eom",
656       "Does this drive require an MTBSF after MTEOM in order to append?" );
657
658     device_property_fill_and_register(&device_property_nonblocking_open,
659                                       G_TYPE_BOOLEAN,
660                                       "nonblocking_open",
661       "Does this drive require a open with O_NONBLOCK?" );
662
663     device_property_fill_and_register(&device_property_final_filemarks,
664                                       G_TYPE_UINT, "final_filemarks",
665       "How many filemarks to write after the last tape file?" );
666
667     device_property_fill_and_register(&device_property_read_buffer_size,
668                                       G_TYPE_UINT, "read_buffer_size",
669       "(deprecated name for READ_BLOCK_SIZE)");
670
671     /* Then the device itself */
672     register_device(tape_device_factory, device_prefix_list);
673 }
674
675 /* Open the tape device, trying various combinations of O_RDWR and
676    O_NONBLOCK.  Returns -1 and calls device_set_error for errors
677    On Linux, with O_NONBLOCK, the kernel just checks the state once,
678    whereas it checks it every second for ST_BLOCK_SECONDS if O_NONBLOCK is
679    not given.  Amanda already have the code to poll, we want open to check
680    the state only once. */
681
682 static int try_open_tape_device(TapeDevice * self, char * device_filename) {
683     int fd;
684     int save_errno;
685     DeviceStatusFlags new_status;
686
687 #ifdef O_NONBLOCK
688     int nonblocking = 0;
689
690     if (self->nonblocking_open) {
691         nonblocking = O_NONBLOCK;
692     }
693 #endif
694
695 #ifdef O_NONBLOCK
696     fd  = robust_open(device_filename, O_RDWR | nonblocking, 0);
697     save_errno = errno;
698     if (fd < 0 && nonblocking && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
699         /* Maybe we don't support O_NONBLOCK for tape devices. */
700         fd = robust_open(device_filename, O_RDWR, 0);
701         save_errno = errno;
702     }
703 #else
704     fd = robust_open(device_filename, O_RDWR, 0);
705     save_errno = errno;
706 #endif
707     if (fd >= 0) {
708         self->write_open_errno = 0;
709     } else {
710         if (errno == EACCES || errno == EPERM
711 #ifdef EROFS
712                             || errno == EROFS
713 #endif
714            ) {
715             /* Device is write-protected. */
716             self->write_open_errno = errno;
717 #ifdef O_NONBLOCK
718             fd = robust_open(device_filename, O_RDONLY | nonblocking, 0);
719             save_errno = errno;
720             if (fd < 0 && nonblocking && (save_errno == EWOULDBLOCK || save_errno == EINVAL)) {
721                 fd = robust_open(device_filename, O_RDONLY, 0);
722                 save_errno = errno;
723             }
724 #else
725             fd = robust_open(device_filename, O_RDONLY, 0);
726             save_errno = errno;
727 #endif
728         }
729     }
730 #ifdef O_NONBLOCK
731     /* Clear O_NONBLOCK for operations from now on. */
732     if (fd >= 0 && nonblocking)
733         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
734     errno = save_errno;
735     /* function continues after #endif */
736
737 #endif /* O_NONBLOCK */
738
739     if (fd < 0) {
740         DeviceStatusFlags status_flag = 0;
741         if (errno == EBUSY)
742             status_flag = DEVICE_STATUS_DEVICE_BUSY;
743         else
744             status_flag = DEVICE_STATUS_DEVICE_ERROR;
745         device_set_error(DEVICE(self),
746             vstrallocf(_("Can't open tape device %s: %s"), self->private->device_filename, strerror(errno)),
747             status_flag);
748         return -1;
749     }
750
751     /* Check that this is actually a tape device. */
752     new_status = tape_is_tape_device(fd);
753     if (new_status & DEVICE_STATUS_DEVICE_ERROR) {
754         device_set_error(DEVICE(self),
755             vstrallocf(_("File %s is not a tape device"), self->private->device_filename),
756             new_status);
757         robust_close(fd);
758         return -1;
759     }
760     if (new_status & DEVICE_STATUS_VOLUME_MISSING) {
761         device_set_error(DEVICE(self),
762             vstrallocf(_("Tape device %s is not ready or is empty"), self->private->device_filename),
763             new_status);
764         robust_close(fd);
765         return -1;
766     }
767
768     new_status = tape_is_ready(fd, self);
769     if (new_status & DEVICE_STATUS_VOLUME_MISSING) {
770         device_set_error(DEVICE(self),
771             vstrallocf(_("Tape device %s is empty"), self->private->device_filename),
772             new_status);
773         robust_close(fd);
774         return -1;
775     }
776     if (new_status != DEVICE_STATUS_SUCCESS) {
777         device_set_error(DEVICE(self),
778             vstrallocf(_("Tape device %s is not ready or is empty"), self->private->device_filename),
779             new_status);
780         robust_close(fd);
781         return -1;
782     }
783
784     return fd;
785 }
786
787 static void
788 tape_device_open_device (Device * dself, char * device_name,
789                         char * device_type, char * device_node) {
790     TapeDevice * self;
791     GValue val;
792
793     self = TAPE_DEVICE(dself);
794
795     self->fd = -1;
796     self->private->device_filename = stralloc(device_node);
797
798     /* Set tape drive/OS info */
799     bzero(&val, sizeof(val));
800     g_value_init(&val, G_TYPE_BOOLEAN);
801
802     self->fsf = TRUE;
803     g_value_set_boolean(&val, self->fsf);
804     device_set_simple_property(dself, PROPERTY_FSF, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
805
806     self->fsf_after_filemark = DEFAULT_FSF_AFTER_FILEMARK;
807     g_value_set_boolean(&val, self->fsf_after_filemark);
808     device_set_simple_property(dself, PROPERTY_FSF_AFTER_FILEMARK, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
809
810     self->bsf = TRUE;
811     g_value_set_boolean(&val, self->bsf);
812     device_set_simple_property(dself, PROPERTY_BSF, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
813
814     self->fsr = TRUE;
815     g_value_set_boolean(&val, self->fsr);
816     device_set_simple_property(dself, PROPERTY_FSR, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
817
818     self->bsr = TRUE;
819     g_value_set_boolean(&val, self->bsr);
820     device_set_simple_property(dself, PROPERTY_BSR, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
821
822     self->eom = TRUE;
823     g_value_set_boolean(&val, self->eom);
824     device_set_simple_property(dself, PROPERTY_EOM, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
825
826     self->leom = FALSE;
827     g_value_set_boolean(&val, self->leom);
828     device_set_simple_property(dself, PROPERTY_LEOM, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
829
830     self->bsf_after_eom = FALSE;
831     g_value_set_boolean(&val, self->bsf_after_eom);
832     device_set_simple_property(dself, PROPERTY_BSF_AFTER_EOM, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
833
834     g_value_unset(&val);
835     g_value_init(&val, G_TYPE_UINT);
836
837     self->final_filemarks = 2;
838     g_value_set_uint(&val, self->final_filemarks);
839     device_set_simple_property(dself, PROPERTY_FINAL_FILEMARKS, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT);
840
841     g_value_unset(&val);
842
843     /* Chain up */
844     if (parent_class->open_device) {
845         parent_class->open_device(dself, device_name, device_type, device_node);
846     }
847 }
848
849
850 static DeviceStatusFlags tape_device_read_label(Device * dself) {
851     TapeDevice * self;
852     char * header_buffer;
853     int buffer_len;
854     IoResult result;
855     dumpfile_t *header;
856     DeviceStatusFlags new_status;
857     char *msg = NULL;
858
859     self = TAPE_DEVICE(dself);
860
861     amfree(dself->volume_label);
862     amfree(dself->volume_time);
863     dumpfile_free(dself->volume_header);
864     dself->volume_header = NULL;
865
866     if (device_in_error(self)) return dself->status;
867
868     if (self->fd == -1) {
869         self->fd = try_open_tape_device(self, self->private->device_filename);
870         /* if the open failed, then try_open_tape_device already set the
871          * approppriate error status */
872         if (self->fd == -1)
873             return dself->status;
874     }
875
876     /* Rewind it. */
877     if (!tape_rewind(self->fd)) {
878         device_set_error(dself,
879             vstrallocf(_("Error rewinding device %s to read label: %s"),
880                     self->private->device_filename, strerror(errno)),
881               DEVICE_STATUS_DEVICE_ERROR
882             | DEVICE_STATUS_VOLUME_ERROR);
883         return dself->status;
884     }
885
886     buffer_len = tape_device_read_size(self);
887     header_buffer = malloc(buffer_len);
888     result = tape_device_robust_read(self, header_buffer, &buffer_len, &msg);
889
890     if (result != RESULT_SUCCESS) {
891         free(header_buffer);
892         tape_rewind(self->fd);
893         /* I/O error. */
894         switch (result) {
895         case RESULT_NO_DATA:
896             msg = stralloc(_("no data"));
897             new_status = (DEVICE_STATUS_VOLUME_ERROR |
898                           DEVICE_STATUS_VOLUME_UNLABELED);
899             header = dself->volume_header = g_new(dumpfile_t, 1);
900             fh_init(header);
901             break;
902
903         case RESULT_SMALL_BUFFER:
904             msg = stralloc(_("block size too small"));
905             new_status = (DEVICE_STATUS_DEVICE_ERROR |
906                           DEVICE_STATUS_VOLUME_ERROR);
907             header = dself->volume_header = g_new(dumpfile_t, 1);
908             fh_init(header);
909             header->type = F_WEIRD;
910             break;
911
912         default:
913             msg = stralloc(_("unknown error"));
914         case RESULT_ERROR:
915             new_status = (DEVICE_STATUS_DEVICE_ERROR |
916                           DEVICE_STATUS_VOLUME_ERROR |
917                           DEVICE_STATUS_VOLUME_UNLABELED);
918             break;
919         }
920         device_set_error(dself,
921                  g_strdup_printf(_("Error reading Amanda header: %s"),
922                         msg? msg : _("unknown error")),
923                  new_status);
924         amfree(msg);
925         return dself->status;
926     }
927
928     dself->header_block_size = buffer_len;
929     header = dself->volume_header = g_new(dumpfile_t, 1);
930     fh_init(header);
931
932     parse_file_header(header_buffer, header, buffer_len);
933     amfree(header_buffer);
934     if (header->type != F_TAPESTART) {
935         device_set_error(dself,
936                 stralloc(_("No tapestart header -- unlabeled device?")),
937                 DEVICE_STATUS_VOLUME_UNLABELED);
938         return dself->status;
939     }
940
941     dself->volume_label = g_strdup(header->name);
942     dself->volume_time = g_strdup(header->datestamp);
943     /* dself->volume_header is already set */
944
945     device_set_error(dself, NULL, DEVICE_STATUS_SUCCESS);
946
947     return dself->status;
948 }
949
950 static gboolean
951 tape_device_write_block(Device * pself, guint size, gpointer data) {
952     TapeDevice * self;
953     char *replacement_buffer = NULL;
954     IoResult result;
955     char *msg = NULL;
956
957     self = TAPE_DEVICE(pself);
958
959     g_assert(self->fd >= 0);
960     if (device_in_error(self)) return FALSE;
961
962     /* zero out to the end of a short block -- tape devices only write
963      * whole blocks. */
964     if (size < pself->block_size) {
965         replacement_buffer = malloc(pself->block_size);
966         memcpy(replacement_buffer, data, size);
967         bzero(replacement_buffer+size, pself->block_size-size);
968
969         data = replacement_buffer;
970         size = pself->block_size;
971     }
972
973     result = tape_device_robust_write(self, data, size, &msg);
974     amfree(replacement_buffer);
975
976     switch (result) {
977         case RESULT_SUCCESS:
978             break;
979
980         case RESULT_NO_SPACE:
981             device_set_error(pself,
982                 stralloc(_("No space left on device")),
983                 DEVICE_STATUS_VOLUME_ERROR);
984             pself->is_eom = TRUE;
985             return FALSE;
986
987         default:
988             msg = stralloc(_("unknown error"));
989         case RESULT_ERROR:
990             device_set_error(pself,
991                 g_strdup_printf(_("Error writing block: %s"), msg),
992                 DEVICE_STATUS_DEVICE_ERROR);
993             amfree(msg);
994             return FALSE;
995     }
996
997     pself->block++;
998     g_mutex_lock(pself->device_mutex);
999     pself->bytes_written += size;
1000     g_mutex_unlock(pself->device_mutex);
1001
1002     return TRUE;
1003 }
1004
1005 static int tape_device_read_block (Device * pself, gpointer buf,
1006                                    int * size_req) {
1007     TapeDevice * self;
1008     int size;
1009     IoResult result;
1010     gssize read_block_size = tape_device_read_size(pself);
1011     char *msg = NULL;
1012
1013     self = TAPE_DEVICE(pself);
1014
1015     g_assert(self->fd >= 0);
1016     if (device_in_error(self)) return -1;
1017
1018     g_assert(read_block_size < INT_MAX); /* data type mismatch */
1019     if (buf == NULL || *size_req < (int)read_block_size) {
1020         /* Just a size query. */
1021         *size_req = (int)read_block_size;
1022         return 0;
1023     }
1024
1025     size = *size_req;
1026     result = tape_device_robust_read(self, buf, &size, &msg);
1027     switch (result) {
1028     case RESULT_SUCCESS:
1029         *size_req = size;
1030         pself->block++;
1031         g_mutex_lock(pself->device_mutex);
1032         pself->bytes_read += size;
1033         g_mutex_unlock(pself->device_mutex);
1034         return size;
1035     case RESULT_SMALL_BUFFER: {
1036         gsize new_size;
1037         GValue newval;
1038
1039         /* If this happens, it means that we have:
1040          *     (next block size) > (buffer size) >= (read_block_size)
1041          * The solution is to ask for an even bigger buffer. We also play
1042          * some games to refrain from reading above the SCSI limit or from
1043          * integer overflow.  Note that not all devices will tell us about
1044          * this problem -- some will just discard the "extra" data. */
1045         new_size = MIN(INT_MAX/2 - 1, *size_req) * 2;
1046         if (new_size > LARGEST_BLOCK_ESTIMATE &&
1047             *size_req < LARGEST_BLOCK_ESTIMATE) {
1048             new_size = LARGEST_BLOCK_ESTIMATE;
1049         }
1050         g_assert (new_size > (gsize)*size_req);
1051
1052         g_info("Device %s indicated blocksize %zd was too small; using %zd.",
1053             pself->device_name, (gsize)*size_req, new_size);
1054         *size_req = (int)new_size;
1055         self->private->read_block_size = new_size;
1056
1057         bzero(&newval, sizeof(newval));
1058         g_value_init(&newval, G_TYPE_UINT);
1059         g_value_set_uint(&newval, self->private->read_block_size);
1060         device_set_simple_property(pself, PROPERTY_READ_BLOCK_SIZE,
1061                 &newval, PROPERTY_SURETY_GOOD, PROPERTY_SOURCE_DETECTED);
1062         g_value_unset(&newval);
1063
1064         return 0;
1065     }
1066     case RESULT_NO_DATA:
1067         pself->is_eof = TRUE;
1068         g_mutex_lock(pself->device_mutex);
1069         pself->in_file = FALSE;
1070         g_mutex_unlock(pself->device_mutex);
1071         device_set_error(pself,
1072             stralloc(_("EOF")),
1073             DEVICE_STATUS_SUCCESS);
1074         return -1;
1075
1076     default:
1077         msg = stralloc(_("unknown error"));
1078     case RESULT_ERROR:
1079         device_set_error(pself,
1080             vstrallocf(_("Error reading from tape device: %s"), msg),
1081             DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1082         amfree(msg);
1083         return -1;
1084     }
1085
1086     g_assert_not_reached();
1087 }
1088
1089 /* Just a helper function for tape_device_start(). */
1090 static gboolean write_tapestart_header(TapeDevice * self, char * label,
1091                                        char * timestamp) {
1092      IoResult result;
1093      dumpfile_t * header;
1094      char * header_buf;
1095      Device * d_self = (Device*)self;
1096      char *msg = NULL;
1097
1098      tape_rewind(self->fd);
1099
1100      header = make_tapestart_header(d_self, label, timestamp);
1101      g_assert(header != NULL);
1102      header_buf = device_build_amanda_header(d_self, header, NULL);
1103      if (header_buf == NULL) {
1104          device_set_error(d_self,
1105             stralloc(_("Tapestart header won't fit in a single block!")),
1106             DEVICE_STATUS_DEVICE_ERROR);
1107          dumpfile_free(header);
1108          return FALSE;
1109      }
1110      dumpfile_free(d_self->volume_header);
1111      d_self->volume_header = NULL;
1112
1113      result = tape_device_robust_write(self, header_buf, d_self->block_size, &msg);
1114      if (result != RESULT_SUCCESS) {
1115         device_set_error(d_self,
1116             g_strdup_printf(_("Error writing tapestart header: %s"),
1117                         (result == RESULT_ERROR)? msg : _("out of space")),
1118             DEVICE_STATUS_DEVICE_ERROR);
1119
1120         if (result == RESULT_NO_SPACE)
1121             d_self->is_eom = TRUE;
1122
1123         amfree(msg);
1124         dumpfile_free(header);
1125         amfree(header_buf);
1126         return FALSE;
1127      }
1128
1129      d_self->header_block_size = d_self->block_size;
1130      amfree(header_buf);
1131
1132      if (!tape_weof(self->fd, 1)) {
1133         device_set_error(d_self,
1134                          vstrallocf(_("Error writing filemark: %s"),
1135                                     strerror(errno)),
1136                          DEVICE_STATUS_DEVICE_ERROR|DEVICE_STATUS_VOLUME_ERROR);
1137         /* can't tell if this was EOM or not, so assume it is */
1138         d_self->is_eom = TRUE;
1139         dumpfile_free(header);
1140         return FALSE;
1141      }
1142
1143      d_self->volume_header = header;
1144      return TRUE;
1145 }
1146
1147 static gboolean
1148 tape_device_start (Device * d_self, DeviceAccessMode mode, char * label,
1149                    char * timestamp) {
1150     TapeDevice * self;
1151
1152     self = TAPE_DEVICE(d_self);
1153
1154     if (device_in_error(self)) return FALSE;
1155
1156     if (self->fd == -1) {
1157         self->fd = try_open_tape_device(self, self->private->device_filename);
1158         /* if the open failed, then try_open_tape_device already set the
1159          * approppriate error status */
1160         if (self->fd == -1)
1161             return FALSE;
1162     }
1163
1164     if (mode != ACCESS_WRITE && d_self->volume_label == NULL) {
1165         /* we need a labeled volume for APPEND and READ */
1166         if (tape_device_read_label(d_self) != DEVICE_STATUS_SUCCESS)
1167             return FALSE;
1168     }
1169
1170     d_self->access_mode = mode;
1171     g_mutex_lock(d_self->device_mutex);
1172     d_self->in_file = FALSE;
1173     g_mutex_unlock(d_self->device_mutex);
1174
1175     if (IS_WRITABLE_ACCESS_MODE(mode)) {
1176         if (self->write_open_errno != 0) {
1177             /* We tried and failed to open the device in write mode. */
1178             device_set_error(d_self,
1179                 vstrallocf(_("Can't open tape device %s for writing: %s"),
1180                             self->private->device_filename, strerror(self->write_open_errno)),
1181                 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1182             return FALSE;
1183         } else if (!tape_rewind(self->fd)) {
1184             device_set_error(d_self,
1185                 vstrallocf(_("Error rewinding device to start: %s"), strerror(errno)),
1186                 DEVICE_STATUS_DEVICE_ERROR);
1187             return FALSE;
1188         }
1189     }
1190
1191     /* Position the tape */
1192     switch (mode) {
1193     case ACCESS_APPEND:
1194         if (d_self->volume_label == NULL && device_read_label(d_self) != DEVICE_STATUS_SUCCESS) {
1195             /* device_read_label already set our error message */
1196             return FALSE;
1197         }
1198
1199         if (!tape_device_eod(self)) {
1200             device_set_error(d_self,
1201                 vstrallocf(_("Couldn't seek to end of tape: %s"), strerror(errno)),
1202                 DEVICE_STATUS_DEVICE_ERROR);
1203             return FALSE;
1204         }
1205         break;
1206
1207     case ACCESS_READ:
1208         if (d_self->volume_label == NULL && device_read_label(d_self) != DEVICE_STATUS_SUCCESS) {
1209             /* device_read_label already set our error message */
1210             return FALSE;
1211         }
1212
1213         if (!tape_rewind(self->fd)) {
1214             device_set_error(d_self,
1215                 vstrallocf(_("Error rewinding device after reading label: %s"), strerror(errno)),
1216                 DEVICE_STATUS_DEVICE_ERROR);
1217             return FALSE;
1218         }
1219         d_self->file = 0;
1220         break;
1221
1222     case ACCESS_WRITE:
1223         if (!write_tapestart_header(self, label, timestamp)) {
1224             /* write_tapestart_header already set the error status */
1225             return FALSE;
1226         }
1227
1228         d_self->volume_label = newstralloc(d_self->volume_label, label);
1229         d_self->volume_time = newstralloc(d_self->volume_time, timestamp);
1230
1231         /* unset the VOLUME_UNLABELED flag, if it was set */
1232         device_set_error(d_self, NULL, DEVICE_STATUS_SUCCESS);
1233         d_self->file = 0;
1234         break;
1235
1236     default:
1237         g_assert_not_reached();
1238     }
1239
1240     return TRUE;
1241 }
1242
1243 static gboolean tape_device_start_file(Device * d_self,
1244                                        dumpfile_t * info) {
1245     TapeDevice * self;
1246     IoResult result;
1247     char * amanda_header;
1248     char *msg = NULL;
1249
1250     self = TAPE_DEVICE(d_self);
1251
1252     g_assert(self->fd >= 0);
1253     if (device_in_error(self)) return FALSE;
1254
1255     /* set the blocksize in the header properly */
1256     info->blocksize = d_self->block_size;
1257
1258     /* Make the Amanda header suitable for writing to the device. */
1259     /* Then write the damn thing. */
1260     amanda_header = device_build_amanda_header(d_self, info, NULL);
1261     if (amanda_header == NULL) {
1262         device_set_error(d_self,
1263             stralloc(_("Amanda file header won't fit in a single block!")),
1264             DEVICE_STATUS_DEVICE_ERROR);
1265         return FALSE;
1266     }
1267
1268     result = tape_device_robust_write(self, amanda_header, d_self->block_size, &msg);
1269     if (result != RESULT_SUCCESS) {
1270         device_set_error(d_self,
1271             vstrallocf(_("Error writing file header: %s"),
1272                         (result == RESULT_ERROR)? msg : _("out of space")),
1273             DEVICE_STATUS_DEVICE_ERROR);
1274
1275         if (result == RESULT_NO_SPACE)
1276             d_self->is_eom = TRUE;
1277
1278         amfree(amanda_header);
1279         amfree(msg);
1280         return FALSE;
1281     }
1282     amfree(amanda_header);
1283
1284     /* arrange the file numbers correctly */
1285     d_self->block = 0;
1286     if (d_self->file >= 0)
1287         d_self->file ++;
1288     g_mutex_lock(d_self->device_mutex);
1289     d_self->in_file = TRUE;
1290     d_self->bytes_written = 0;
1291     g_mutex_unlock(d_self->device_mutex);
1292     return TRUE;
1293 }
1294
1295 static gboolean
1296 tape_device_finish_file (Device * d_self) {
1297     TapeDevice * self;
1298
1299     self = TAPE_DEVICE(d_self);
1300     if (device_in_error(d_self)) return FALSE;
1301
1302     if (!tape_weof(self->fd, 1)) {
1303         device_set_error(d_self,
1304                 vstrallocf(_("Error writing filemark: %s"), strerror(errno)),
1305                 DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1306         /* can't tell if this was EOM or not, so assume it is */
1307         d_self->is_eom = TRUE;
1308         return FALSE;
1309     }
1310
1311     g_mutex_lock(d_self->device_mutex);
1312     d_self->in_file = FALSE;
1313     g_mutex_unlock(d_self->device_mutex);
1314     return TRUE;
1315 }
1316
1317 static dumpfile_t *
1318 tape_device_seek_file (Device * d_self, guint file) {
1319     TapeDevice * self;
1320     gint got_file;
1321     int difference;
1322     char * header_buffer;
1323     dumpfile_t * rval;
1324     int buffer_len;
1325     IoResult result;
1326     char *msg;
1327
1328     self = TAPE_DEVICE(d_self);
1329
1330     if (device_in_error(self)) return NULL;
1331
1332     difference = file - d_self->file;
1333
1334     /* Check if we already read a filemark. */
1335     /* If we already read a filemark and the drive automaticaly goes to the
1336        next file, then we must reduce the difference by one. */
1337     if (d_self->is_eof && !self->fsf_after_filemark) {
1338         difference --;
1339     }
1340
1341     d_self->is_eof = FALSE;
1342     d_self->block = 0;
1343     g_mutex_lock(d_self->device_mutex);
1344     d_self->in_file = FALSE;
1345     d_self->bytes_read = 0;
1346     g_mutex_unlock(d_self->device_mutex);
1347
1348 reseek:
1349     if (difference > 0) {
1350         /* Seeking forwards */
1351         if (!tape_device_fsf(self, difference)) {
1352             tape_rewind(self->fd);
1353             device_set_error(d_self,
1354                 vstrallocf(_("Could not seek forward to file %d"), file),
1355                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1356             return NULL;
1357         }
1358     } else { /* (difference <= 0) */
1359         /* Seeking backwards, or to this file itself */
1360
1361         /* if the drive supports bsf, we can do this the fancy way */
1362         if (self->bsf) {
1363             /* bsf one more than the difference */
1364             if (!tape_bsf(self->fd, -difference + 1)) {
1365                 tape_rewind(self->fd);
1366                 device_set_error(d_self,
1367                     vstrallocf(_("Could not seek backward to file %d"), file),
1368                     DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1369                 return NULL;
1370             }
1371
1372             /* now we are on the BOT side of the desired filemark, so FSF to get to the
1373              * EOT side of it */
1374             if (!tape_device_fsf(self, 1)) {
1375                 tape_rewind(self->fd);
1376                 device_set_error(d_self,
1377                     vstrallocf(_("Could not seek forward to file %d"), file),
1378                     DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1379                 return NULL;
1380             }
1381         } else {
1382             /* no BSF, so just rewind and seek forward */
1383             if (!tape_rewind(self->fd)) {
1384                 device_set_error(d_self,
1385                     vstrallocf(_("Could not rewind device while emulating BSF")),
1386                     DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1387                 return FALSE;
1388             }
1389
1390             if (!tape_device_fsf(self, file)) {
1391                 tape_rewind(self->fd);
1392                 device_set_error(d_self,
1393                     vstrallocf(_("Could not seek forward to file %d"), file),
1394                     DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1395                 return NULL;
1396             }
1397         }
1398     }
1399
1400     /* double-check that we're on the right fileno, if possible.  This is most
1401      * likely a programming error if it occurs, but could also be due to a weird
1402      * tape drive or driver (and that would *never* happen, right?) */
1403     got_file = tape_fileno(self->fd);
1404     if (got_file >= 0 && (guint)got_file != file) {
1405         device_set_error(d_self,
1406                 vstrallocf(_("Could not seek to file %d correctly; got %d"),
1407                             file, got_file),
1408                 DEVICE_STATUS_DEVICE_ERROR);
1409         d_self->file = (guint)got_file;
1410         return NULL;
1411     }
1412
1413     buffer_len = tape_device_read_size(d_self);
1414     header_buffer = malloc(buffer_len);
1415     d_self->is_eof = FALSE;
1416     result = tape_device_robust_read(self, header_buffer, &buffer_len, &msg);
1417
1418     if (result != RESULT_SUCCESS) {
1419         free(header_buffer);
1420         tape_rewind(self->fd);
1421         switch (result) {
1422         case RESULT_NO_DATA:
1423             /* If we read 0 bytes, that means we encountered a double
1424              * filemark, which indicates end of tape. This should
1425              * work even with QIC tapes on operating systems with
1426              * proper support. */
1427             d_self->file = file; /* other attributes are already correct */
1428             return make_tapeend_header();
1429
1430         case RESULT_SMALL_BUFFER:
1431             msg = stralloc(_("block size too small"));
1432             break;
1433
1434         default:
1435             msg = stralloc(_("unknown error"));
1436         case RESULT_ERROR:
1437             break;
1438         }
1439         device_set_error(d_self,
1440             g_strdup_printf(_("Error reading Amanda header: %s"), msg),
1441             DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR);
1442         amfree(msg);
1443         return NULL;
1444     }
1445
1446     rval = g_new(dumpfile_t, 1);
1447     parse_file_header(header_buffer, rval, buffer_len);
1448     amfree(header_buffer);
1449     switch (rval->type) {
1450     case F_DUMPFILE:
1451     case F_CONT_DUMPFILE:
1452     case F_SPLIT_DUMPFILE:
1453         break;
1454
1455     case F_NOOP:
1456         /* a NOOP is written on QIC tapes to avoid writing two sequential
1457          * filemarks when closing a device in WRITE or APPEND mode.  In this
1458          * case, we just seek to the next file. */
1459         amfree(rval);
1460         file++;
1461         difference = 1;
1462         goto reseek;
1463
1464     default:
1465         tape_rewind(self->fd);
1466         device_set_error(d_self,
1467             stralloc(_("Invalid amanda header while reading file header")),
1468             DEVICE_STATUS_VOLUME_ERROR);
1469         amfree(rval);
1470         return NULL;
1471     }
1472
1473     g_mutex_lock(d_self->device_mutex);
1474     d_self->in_file = TRUE;
1475     g_mutex_unlock(d_self->device_mutex);
1476     d_self->file = file;
1477
1478     return rval;
1479 }
1480
1481 static gboolean
1482 tape_device_seek_block (Device * d_self, guint64 block) {
1483     TapeDevice * self;
1484     int difference;
1485
1486     self = TAPE_DEVICE(d_self);
1487
1488     if (device_in_error(self)) return FALSE;
1489
1490     difference = block - d_self->block;
1491
1492     if (difference > 0) {
1493         if (!tape_device_fsr(self, difference)) {
1494             device_set_error(d_self,
1495                 vstrallocf(_("Could not seek forward to block %ju: %s"), (uintmax_t)block, strerror(errno)),
1496                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1497             return FALSE;
1498         }
1499     } else if (difference < 0) {
1500         if (!tape_device_bsr(self, difference, d_self->file, d_self->block)) {
1501             device_set_error(d_self,
1502                 vstrallocf(_("Could not seek backward to block %ju: %s"), (uintmax_t)block, strerror(errno)),
1503                 DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_DEVICE_ERROR);
1504             return FALSE;
1505         }
1506     }
1507
1508     d_self->block = block;
1509     return TRUE;
1510 }
1511
1512 static gboolean
1513 tape_device_eject (Device * d_self) {
1514     TapeDevice * self;
1515
1516     self = TAPE_DEVICE(d_self);
1517
1518     if (device_in_error(self)) return FALSE;
1519
1520     /* Open the device if not already opened */
1521     if (self->fd == -1) {
1522         self->fd = try_open_tape_device(self, self->private->device_filename);
1523         /* if the open failed, then try_open_tape_device already set the
1524          * approppriate error status */
1525         if (self->fd == -1)
1526             return FALSE;
1527     }
1528
1529     /* Rewind it. */
1530     if (!tape_rewind(self->fd)) {
1531         device_set_error(d_self,
1532             vstrallocf(_("Error rewinding device %s before ejecting: %s"),
1533                        self->private->device_filename, strerror(errno)),
1534               DEVICE_STATUS_DEVICE_ERROR
1535             | DEVICE_STATUS_VOLUME_ERROR);
1536         return FALSE;
1537     }
1538
1539     if (tape_offl(self->fd))
1540         return TRUE;
1541
1542     device_set_error(d_self,
1543         vstrallocf(_("Error ejecting device %s: %s\n"),
1544                    self->private->device_filename, strerror(errno)),
1545           DEVICE_STATUS_DEVICE_ERROR);
1546
1547     return FALSE;
1548 }
1549
1550 static gboolean
1551 tape_device_finish (Device * d_self) {
1552     TapeDevice * self;
1553     char *msg = NULL;
1554
1555     self = TAPE_DEVICE(d_self);
1556
1557     if (device_in_error(self))
1558         goto finish_error;
1559
1560     /* if we're already in ACCESS_NULL, then there are no filemarks or anything
1561      * to worry about, but we need to release the kernel device */
1562     if (d_self->access_mode == ACCESS_NULL) {
1563         robust_close(self->fd);
1564         self->fd = -1;
1565         return TRUE;
1566     }
1567
1568     /* Polish off this file, if relevant. */
1569     g_mutex_lock(d_self->device_mutex);
1570     if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
1571         g_mutex_unlock(d_self->device_mutex);
1572         if (!device_finish_file(d_self)) {
1573             goto finish_error;
1574         }
1575     } else {
1576         g_mutex_unlock(d_self->device_mutex);
1577     }
1578
1579     /* Straighten out the filemarks.  We already wrote one in finish_file, and
1580      * the device driver will write another filemark when we rewind.  This means
1581      * that, if we do nothing, we'll get two filemarks.  If final_filemarks is
1582      * 1, this would be wrong, so in this case we insert a F_NOOP header between
1583      * the two filemarks. */
1584     if (self->final_filemarks == 1 &&
1585         IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) {
1586         dumpfile_t file;
1587         char *header;
1588         int result;
1589
1590         /* write a F_NOOP header */
1591         fh_init(&file);
1592         file.type = F_NOOP;
1593         header = device_build_amanda_header(d_self, &file, NULL);
1594         if (!header) {
1595             device_set_error(d_self,
1596                 stralloc(_("Amanda file header won't fit in a single block!")),
1597                 DEVICE_STATUS_DEVICE_ERROR);
1598             goto finish_error;
1599         }
1600
1601         result = tape_device_robust_write(self, header, d_self->block_size, &msg);
1602         if (result != RESULT_SUCCESS) {
1603             device_set_error(d_self,
1604                 vstrallocf(_("Error writing file header: %s"),
1605                             (result == RESULT_ERROR)? msg : _("out of space")),
1606                 DEVICE_STATUS_DEVICE_ERROR);
1607             amfree(header);
1608             amfree(msg);
1609             goto finish_error;
1610         }
1611         amfree(header);
1612     }
1613
1614     /* Rewind (the kernel will write a filemark first) */
1615     if (!tape_rewind(self->fd)) {
1616         device_set_error(d_self,
1617             vstrallocf(_("Couldn't rewind device to finish: %s"), strerror(errno)),
1618             DEVICE_STATUS_DEVICE_ERROR);
1619         goto finish_error;
1620     }
1621
1622     d_self->is_eof = FALSE;
1623     d_self->access_mode = ACCESS_NULL;
1624
1625     /* release the kernel's device */
1626     robust_close(self->fd);
1627     self->fd = -1;
1628
1629     return TRUE;
1630
1631 finish_error:
1632     d_self->access_mode = ACCESS_NULL;
1633
1634     /* release the kernel's device */
1635     robust_close(self->fd);
1636     self->fd = -1;
1637
1638     return FALSE;
1639 }
1640
1641 /* Works just like read(), except for the following:
1642  * 1) Retries on EINTR & friends.
1643  * 2) Stores count in parameter, not return value.
1644  * 3) Provides explicit return result.
1645  * *errmsg is only set on RESULT_ERROR.
1646  */
1647 static IoResult
1648 tape_device_robust_read (TapeDevice * self, void * buf, int * count, char **errmsg) {
1649     Device * d_self;
1650     int result;
1651
1652     d_self = (Device*)self;
1653
1654     /* Callers should ensure this. */
1655     g_assert(*count >= 0);
1656
1657     for (;;) {
1658         result = read(self->fd, buf, *count);
1659         if (result > 0) {
1660             /* Success. By definition, we read a full block. */
1661             d_self->is_eof = FALSE;
1662             *count = result;
1663             return RESULT_SUCCESS;
1664         } else if (result == 0) {
1665             d_self->is_eof = TRUE;
1666             return RESULT_NO_DATA;
1667         } else {
1668             if (0
1669 #ifdef EAGAIN
1670                 || errno == EAGAIN
1671 #endif
1672 #ifdef EWOULDBLOCK
1673                 || errno == EWOULDBLOCK
1674 #endif
1675 #ifdef EINTR
1676                 || errno == EINTR
1677 #endif
1678                 ) {
1679                 /* Interrupted system call */
1680                 continue;
1681             } else if ((0
1682 #ifdef ENOMEM
1683                         || errno == ENOMEM /* bad user-space buffer */
1684 #endif
1685 #ifdef EOVERFLOW
1686                         || errno == EOVERFLOW /* bad kernel-space buffer */
1687 #endif
1688 #ifdef EINVAL
1689                         || errno == EINVAL /* ??? */
1690 #endif
1691                         )) {
1692                 /* Buffer too small. */
1693                 g_warning("Buffer is too small (%d bytes) from %s: %s",
1694                         *count, self->private->device_filename, strerror(errno));
1695                 return RESULT_SMALL_BUFFER;
1696             } else {
1697                 *errmsg = g_strdup_printf(_("Error reading %d bytes from %s: %s"),
1698                         *count, self->private->device_filename, strerror(errno));
1699                 return RESULT_ERROR;
1700             }
1701         }
1702     }
1703
1704     g_assert_not_reached();
1705 }
1706
1707 /* Kernel workaround: If needed, poke the kernel so it doesn't fail.
1708    at the 2GB boundry. Parameters are G_GNUC_UNUSED in case NEED_RESETOFS
1709    is not defined. */
1710 static void check_resetofs(TapeDevice * self G_GNUC_UNUSED,
1711                            int count G_GNUC_UNUSED) {
1712 #ifdef NEED_RESETOFS
1713     Device * d_self;
1714     int result;
1715
1716     d_self = (Device*)self;
1717
1718     self->private->write_count += count;
1719     if (self->private->write_count < RESETOFS_THRESHOLD) {
1720         return;
1721     }
1722
1723     result = lseek(self->fd, 0, SEEK_SET);
1724     if (result < 0) {
1725         g_warning(_("lseek() failed during kernel 2GB workaround: %s"),
1726                strerror(errno));
1727     }
1728 #endif
1729 }
1730
1731 /* *errmsg is only set on RESULT_ERROR */
1732 static IoResult
1733 tape_device_robust_write (TapeDevice * self, void * buf, int count, char **errmsg) {
1734     Device * d_self;
1735     int result;
1736     gboolean retry = FALSE;
1737
1738     d_self = (Device*)self;
1739
1740     check_resetofs(self, count);
1741
1742     for (;;) {
1743         result = write(self->fd, buf, count);
1744
1745         /* Success. */
1746         if (result == count)
1747             return RESULT_SUCCESS;
1748
1749         if (result > 0) {
1750             /* write() returned a short count. This should not happen if the block sizes
1751              * are properly aligned. */
1752             *errmsg = g_strdup_printf("Short write on tape device: Tried %d, got %d.  Is "
1753                             "the drive using a block size smaller than %d bytes?",
1754                                 count, result, count);
1755             return RESULT_ERROR;
1756         }
1757
1758         /* Detect LEOM (early warning) and handle properly
1759          *
1760          * FreeBSD: 0-length write; next write will succeed
1761          *   http://lists.freebsd.org/pipermail/freebsd-scsi/2010-June/004414.html
1762          *
1763          * Solaris: 0-length write; next write will succeed
1764          *   (from Matthew Jacob on FreeBSD thread)
1765          *
1766          * Linux: -1/ENOSPC; next write will succeed
1767          *   http://www.mjmwired.net/kernel/Documentation/scsi/st.txt
1768          *
1769          * HP/UX: -1/ENOSPC; next write will succeed
1770          *   http://www.adssasia.com/Manual/IBM%203581%20tape%20autoloader.pdf
1771          */
1772         if (result == 0
1773 #ifdef ENOSPC
1774                         || (result < 0 && errno == ENOSPC)
1775 #endif
1776         ) {
1777             /* if we've retried once already, then we're probably really out of space */
1778             if (retry)
1779                 return RESULT_NO_SPACE;
1780             retry = TRUE;
1781             d_self->is_eom = TRUE;
1782
1783             g_debug("empty write to tape; treating as LEOM early warning and retrying");
1784             continue;
1785         }
1786
1787         /* at this point result < 0, so an error occurred - sort out what */
1788
1789         if (0
1790 #ifdef EAGAIN
1791                    || errno == EAGAIN
1792 #endif
1793 #ifdef EWOULDBLOCK
1794                    || errno == EWOULDBLOCK
1795 #endif
1796 #ifdef EINTR
1797                    || errno == EINTR
1798 #endif
1799                    ) {
1800                 /* Interrupted system call */
1801             continue;
1802         } else if (0
1803 #ifdef ENOSPC
1804                    || errno == ENOSPC
1805 #endif
1806 #ifdef EIO
1807                    || errno == EIO
1808 #endif
1809                    ) {
1810             /* Probably EOT. Print a message if we got EIO. */
1811 #ifdef EIO
1812             if (errno == EIO) {
1813                 g_warning(_("Got EIO on %s, assuming end of tape"),
1814                         self->private->device_filename);
1815             }
1816 #endif
1817             return RESULT_NO_SPACE;
1818         } else {
1819             /* WTF */
1820             *errmsg = vstrallocf(_("Kernel gave unexpected write() result of \"%s\" on device %s"),
1821                             strerror(errno), self->private->device_filename);
1822             return RESULT_ERROR;
1823         }
1824     }
1825
1826     g_assert_not_reached();
1827 }
1828
1829 /* Reads some number of tape blocks into the bit-bucket. If the count
1830    is negative, then we read the rest of the entire file. Returns the
1831    number of blocks read, or -1 if an error occured. If we encounter
1832    EOF (as opposed to some other error) we return the number of blocks
1833    actually read. */
1834 static int drain_tape_blocks(TapeDevice * self, int count) {
1835     char * buffer;
1836     gsize buffer_size;
1837     int i;
1838
1839     buffer_size = tape_device_read_size(self);
1840
1841     buffer = malloc(buffer_size);
1842
1843     for (i = 0; i < count || count < 0;) {
1844         int result;
1845
1846         result = read(self->fd, buffer, buffer_size);
1847         if (result > 0) {
1848             i ++;
1849             continue;
1850         } else if (result == 0) {
1851             amfree(buffer);
1852             return i;
1853         } else {
1854             /* First check for interrupted system call. */
1855             if (0
1856 #ifdef EAGAIN
1857                 || errno == EAGAIN
1858 #endif
1859 #ifdef EWOULDBLOCK
1860                 || errno == EWOULDBLOCK
1861 #endif
1862 #ifdef EINTR
1863                 || errno == EINTR
1864 #endif
1865                 ) {
1866                 /* Interrupted system call */
1867                 continue;
1868             } else if (0
1869 #ifdef ENOSPC
1870                        || errno == ENOSPC /* bad user-space buffer */
1871 #endif
1872 #ifdef EOVERFLOW
1873                        || errno == EOVERFLOW /* bad kernel-space buffer */
1874 #endif
1875 #ifdef EINVAL
1876                        || errno == EINVAL /* ??? */
1877 #endif
1878                        ) {
1879                 /* The buffer may not be big enough. But the OS is not
1880                    100% clear. We double the buffer and try again, but
1881                    in no case allow a buffer bigger than 32 MB. */
1882                 buffer_size *= 2;
1883
1884                 if (buffer_size > 32*1024*1024) {
1885                     amfree(buffer);
1886                     return -1;
1887                 } else {
1888                     buffer = realloc(buffer, buffer_size);
1889                     continue;
1890                 }
1891             }
1892         }
1893     }
1894
1895     amfree(buffer);
1896     return count;
1897 }
1898
1899 static gboolean
1900 tape_device_fsf (TapeDevice * self, guint count) {
1901     if (self->fsf) {
1902         return tape_fsf(self->fd, count);
1903     } else {
1904         guint i;
1905         for (i = 0; i < count; i ++) {
1906             if (drain_tape_blocks(self, -1) < 0)
1907                 return FALSE;
1908         }
1909         return TRUE;
1910     }
1911 }
1912
1913
1914 static gboolean
1915 tape_device_fsr (TapeDevice * self, guint count) {
1916     if (self->fsr) {
1917         return tape_fsr(self->fd, count);
1918     } else {
1919         int result = drain_tape_blocks(self, count);
1920         return result > 0 && (int)count == result;
1921     }
1922 }
1923
1924 /* Seek back the given number of blocks to block number block within
1925  * the current file, numbered file. */
1926
1927 static gboolean
1928 tape_device_bsr (TapeDevice * self, guint count, guint file, guint block) {
1929     if (self->bsr) {
1930         return tape_bsr(self->fd, count);
1931     } else if (self->bsf && self->fsf) {
1932         /* BSF, FSF to the right side of the filemark, and then FSR. */
1933         if (!tape_bsf(self->fd, 1))
1934             return FALSE;
1935
1936         if (!tape_fsf(self->fd, 1))
1937             return FALSE;
1938
1939         return tape_device_fsr(self, block);
1940     } else {
1941         /* rewind, FSF, and FSR */
1942         if (!tape_rewind(self->fd))
1943             return FALSE;
1944
1945         if (!tape_device_fsf(self, file))
1946             return FALSE;
1947
1948         return tape_device_fsr(self, block);
1949     }
1950     g_assert_not_reached();
1951 }
1952
1953 /* Go to the right place to write more data, and update the file
1954    number if possible. */
1955 static gboolean
1956 tape_device_eod (TapeDevice * self) {
1957     Device * d_self;
1958     int count;
1959
1960     d_self = (Device*)self;
1961
1962     if (self->eom) {
1963         int result;
1964         result = tape_eod(self->fd);
1965         if (result == TAPE_OP_ERROR) {
1966             return FALSE;
1967         } else if (result != TAPE_POSITION_UNKNOWN) {
1968             /* great - we just fast-forwarded to EOD, but don't know where we are, so
1969              * now we have to rewind and drain all of that data.  Warn the user so that
1970              * we can skip the fast-forward-rewind stage on the next run */
1971             g_warning("Seek to end of tape does not give an accurate tape position; set "
1972                       "the EOM property to 0 to avoid useless tape movement.");
1973             /* and set the property so that next time *this* object is opened for
1974              * append, we skip this stage */
1975             self->eom = FALSE;
1976             /* fall through to draining blocks, below */
1977         } else {
1978             /* We drop by 1 because Device will increment the first
1979                time the user does start_file. */
1980             d_self->file = result - 1;
1981             return TRUE;
1982         }
1983     }
1984
1985     if (!tape_rewind(self->fd))
1986         return FALSE;
1987
1988     count = 0;
1989     for (;;) {
1990         /* We alternately read a block and FSF. If the read is
1991            successful, then we are not there yet and should FSF
1992            again. */
1993         int result;
1994         result = drain_tape_blocks(self, 1);
1995         if (result == 1) {
1996             /* More data, FSF. */
1997             tape_device_fsf(self, 1);
1998             count ++;
1999         } else if (result == 0) {
2000             /* Finished. */
2001             d_self->file = count - 1;
2002             return TRUE;
2003         } else {
2004             return FALSE;
2005         }
2006     }
2007 }
2008
2009 static Device *
2010 tape_device_factory (char * device_name, char * device_type, char * device_node) {
2011     Device * rval;
2012     g_assert(0 == strcmp(device_type, "tape"));
2013     rval = DEVICE(g_object_new(TYPE_TAPE_DEVICE, NULL));
2014     device_open_device(rval, device_name, device_type, device_node);
2015     return rval;
2016 }
2017
2018 /*
2019  * Tape Operations using the POSIX interface
2020  */
2021
2022 /* Having one name for every operation would be too easy. */
2023 #if !defined(MTCOMPRESSION) && defined(MTCOMP)
2024 # define MTCOMPRESSION MTCOMP
2025 #endif
2026
2027 #if !defined(MTSETBLK) && defined(MTSETBSIZ)
2028 # define MTSETBLK MTSETBSIZ
2029 #endif
2030
2031 #if !defined(MTEOM) && defined(MTEOD)
2032 # define MTEOM MTEOD
2033 #endif
2034
2035 gboolean tape_rewind(int fd) {
2036     int count = 5;
2037     time_t stop_time;
2038
2039     /* We will retry this for up to 30 seconds or 5 retries,
2040        whichever is less, because some hardware/software combinations
2041        (notably EXB-8200 on FreeBSD) can fail to rewind. */
2042     stop_time = time(NULL) + 30;
2043
2044     while (--count >= 0 && time(NULL) < stop_time) {
2045         struct mtop mt;
2046         mt.mt_op = MTREW;
2047         mt.mt_count = 1;
2048
2049         if (0 == ioctl(fd, MTIOCTOP, &mt))
2050             return TRUE;
2051
2052         sleep(3);
2053     }
2054
2055     return FALSE;
2056 }
2057
2058 gboolean tape_fsf(int fd, guint count) {
2059     struct mtop mt;
2060     mt.mt_op = MTFSF;
2061     mt.mt_count = count;
2062     return 0 == ioctl(fd, MTIOCTOP, &mt);
2063 }
2064
2065 gboolean tape_bsf(int fd, guint count) {
2066     struct mtop mt;
2067     mt.mt_op = MTBSF;
2068     mt.mt_count = count;
2069     return 0 == ioctl(fd, MTIOCTOP, &mt);
2070 }
2071
2072 gboolean tape_fsr(int fd, guint count) {
2073     struct mtop mt;
2074     mt.mt_op = MTFSR;
2075     mt.mt_count = count;
2076     return 0 == ioctl(fd, MTIOCTOP, &mt);
2077 }
2078
2079 gboolean tape_bsr(int fd, guint count) {
2080     struct mtop mt;
2081     mt.mt_op = MTBSR;
2082     mt.mt_count = count;
2083     return 0 == ioctl(fd, MTIOCTOP, &mt);
2084 }
2085
2086 gint tape_fileno(int fd) {
2087     struct mtget get;
2088
2089     if (0 != ioctl(fd, MTIOCGET, &get))
2090         return TAPE_POSITION_UNKNOWN;
2091     if (get.mt_fileno < 0)
2092         return TAPE_POSITION_UNKNOWN;
2093     else
2094         return get.mt_fileno;
2095 }
2096
2097 gint tape_eod(int fd) {
2098     struct mtop mt;
2099     struct mtget get;
2100     mt.mt_op = MTEOM;
2101     mt.mt_count = 1;
2102     if (0 != ioctl(fd, MTIOCTOP, &mt))
2103         return TAPE_OP_ERROR;
2104
2105     /* Ignored result. This is just to flush buffers. */
2106     mt.mt_op = MTNOP;
2107     ioctl(fd, MTIOCTOP, &mt);
2108
2109     if (0 != ioctl(fd, MTIOCGET, &get))
2110         return TAPE_POSITION_UNKNOWN;
2111     if (get.mt_fileno < 0)
2112         return TAPE_POSITION_UNKNOWN;
2113     else
2114         return get.mt_fileno;
2115 }
2116
2117 gboolean tape_weof(int fd, guint8 count) {
2118     struct mtop mt;
2119     mt.mt_op = MTWEOF;
2120     mt.mt_count = count;
2121     return 0 == ioctl(fd, MTIOCTOP, &mt);
2122 }
2123
2124 gboolean tape_setcompression(int fd G_GNUC_UNUSED, 
2125         gboolean on G_GNUC_UNUSED) {
2126 #ifdef MTCOMPRESSION
2127     struct mtop mt;
2128     mt.mt_op = MTCOMPRESSION;
2129     mt.mt_count = on;
2130     return 0 == ioctl(fd, MTIOCTOP, &mt);
2131 #else
2132     return 0;
2133 #endif
2134 }
2135
2136 gboolean tape_offl(int fd) {
2137     struct mtop mt;
2138     int safe_errno;
2139
2140     mt.mt_op = MTOFFL;
2141     mt.mt_count = 1;
2142     if (0 == ioctl(fd, MTIOCTOP, &mt))
2143         return TRUE;
2144
2145     safe_errno = errno;
2146     g_debug("tape_off: ioctl(MTIOCTOP/MTOFFL) failed: %s", strerror(errno));
2147     errno = safe_errno;
2148
2149     return FALSE;
2150 }
2151
2152 DeviceStatusFlags tape_is_tape_device(int fd) {
2153     struct mtop mt;
2154     mt.mt_op = MTNOP;
2155     mt.mt_count = 1;
2156     if (0 == ioctl(fd, MTIOCTOP, &mt)) {
2157         return DEVICE_STATUS_SUCCESS;
2158 #ifdef ENOMEDIUM
2159     } else if (errno == ENOMEDIUM) {
2160         return DEVICE_STATUS_VOLUME_MISSING;
2161 #endif
2162     } else {
2163         g_debug("tape_is_tape_device: ioctl(MTIOCTOP/MTNOP) failed: %s",
2164                  strerror(errno));
2165         if (errno == EIO) {
2166             /* some devices return EIO while the drive is busy loading */
2167             return DEVICE_STATUS_DEVICE_ERROR|DEVICE_STATUS_DEVICE_BUSY;
2168         } else {
2169             return DEVICE_STATUS_DEVICE_ERROR;
2170         }
2171     }
2172 }
2173
2174 DeviceStatusFlags tape_is_ready(int fd, TapeDevice *t_self G_GNUC_UNUSED) {
2175     struct mtget get;
2176     if (0 == ioctl(fd, MTIOCGET, &get)) {
2177 #if defined(GMT_ONLINE) || defined(GMT_DR_OPEN)
2178         if (1
2179 #ifdef GMT_ONLINE
2180             && (t_self->broken_gmt_online || GMT_ONLINE(get.mt_gstat))
2181 #endif
2182 #ifdef GMT_DR_OPEN
2183             && !GMT_DR_OPEN(get.mt_gstat)
2184 #endif
2185             ) {
2186             return DEVICE_STATUS_SUCCESS;
2187         } else {
2188             return DEVICE_STATUS_VOLUME_MISSING;
2189         }
2190 #else /* Neither macro is defined. */
2191         return DEVICE_STATUS_SUCCESS;
2192 #endif
2193     } else {
2194         return DEVICE_STATUS_VOLUME_ERROR;
2195     }
2196 }
2197