X-Git-Url: https://git.gag.com/?p=debian%2Famanda;a=blobdiff_plain;f=device-src%2Ftape-device.c;h=36498ddf8ce54dce6bc0da4942c371b7d205e7c4;hp=ba8f7689f27a91d9a4684cb242c659a8de13279b;hb=b116e9366c7b2ea2c2eb53b0a13df4090e176235;hpb=fd48f3e498442f0cbff5f3606c7c403d0566150e diff --git a/device-src/tape-device.c b/device-src/tape-device.c index ba8f768..36498dd 100644 --- a/device-src/tape-device.c +++ b/device-src/tape-device.c @@ -22,8 +22,17 @@ #include "pipespawn.h" #include /* memset() */ #include "util.h" -#include "tape-device.h" -#include "tape-ops.h" +#include "device.h" + +#ifdef HAVE_SYS_TAPE_H +# include +#endif +#ifdef HAVE_SYS_MTIO_H +# include +#endif +#ifdef HAVE_LIMITS_H +# include +#endif /* This is equal to 2*1024*1024*1024 - 16*1024*1024 - 1, but written explicitly to avoid overflow issues. */ @@ -32,6 +41,41 @@ /* Largest possible block size on SCSI systems. */ #define LARGEST_BLOCK_ESTIMATE (16 * 1024 * 1024) +/* + * Type checking and casting macros + */ + +#define TYPE_TAPE_DEVICE (tape_device_get_type()) +#define TAPE_DEVICE(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), tape_device_get_type(), TapeDevice) +#define TAPE_DEVICE_CONST(obj) G_TYPE_CHECK_INSTANCE_CAST((obj), tape_device_get_type(), TapeDevice const) +#define TAPE_DEVICE_CLASS(klass) G_TYPE_CHECK_CLASS_CAST((klass), tape_device_get_type(), TapeDeviceClass) +#define IS_TAPE_DEVICE(obj) G_TYPE_CHECK_INSTANCE_TYPE((obj), tape_device_get_type ()) +#define TAPE_DEVICE_GET_CLASS(obj) G_TYPE_INSTANCE_GET_CLASS((obj), tape_device_get_type(), TapeDeviceClass) +GType tape_device_get_type (void); + +/* + * Main object structure + */ +typedef struct TapeDevicePrivate_s TapeDevicePrivate; +typedef struct _TapeDevice { + Device __parent__; + + /* It should go without saying that all this stuff is + * look-but-don't-touch. */ + + /* characteristics of the device */ + gboolean fsf, bsf, fsr, bsr, eom, bsf_after_eom, broken_gmt_online; + gboolean leom; + gboolean nonblocking_open, fsf_after_filemark; + int final_filemarks; + + /* 0 if we opened with O_RDWR; error otherwise. */ + gboolean write_open_errno; + int fd; + + TapeDevicePrivate * private; +} TapeDevice; + struct TapeDevicePrivate_s { /* This holds the total number of bytes written to the device, modulus RESETOFS_THRESHOLD. */ @@ -40,6 +84,41 @@ struct TapeDevicePrivate_s { gsize read_block_size; }; +/* + * Class definition + */ + +typedef struct _TapeDeviceClass TapeDeviceClass; +struct _TapeDeviceClass { + DeviceClass __parent__; +}; + +void tape_device_register(void); + +/* useful callback for tape ops */ +void tape_device_set_capabilities(TapeDevice *self, + gboolean fsf, PropertySurety fsf_surety, PropertySource fsf_source, + gboolean fsf_after_filemark, PropertySurety faf_surety, PropertySource faf_source, + gboolean bsf, PropertySurety bsf_surety, PropertySource bsf_source, + gboolean fsr, PropertySurety fsr_surety, PropertySource fsr_source, + gboolean bsr, PropertySurety bsr_surety, PropertySource bsr_source, + gboolean eom, PropertySurety eom_surety, PropertySource eom_source, + gboolean leom, PropertySurety leom_surety, PropertySource leom_source, + gboolean bsf_after_eom, PropertySurety bae_surety, PropertySource bae_source, + guint final_filemarks, PropertySurety ff_surety, PropertySource ff_source); + +/* Real Operations (always return FALSE if not implemented) */ +gboolean tape_rewind(int fd); +gboolean tape_fsf(int fd, guint count); +gboolean tape_bsf(int fd, guint count); +gboolean tape_fsr(int fd, guint count); +gboolean tape_bsr(int fd, guint count); +gint tape_fileno(int fd); + +/* tape_fileno returns tape position file number, or one of these: */ +#define TAPE_OP_ERROR -1 +#define TAPE_POSITION_UNKNOWN -2 + /* Possible (abstracted) results from a system I/O operation. */ typedef enum { RESULT_SUCCESS, @@ -53,28 +132,48 @@ typedef enum { RESULT_MAX } IoResult; -/* - * Our device-specific properties. These are not static because they are - * accessed from the OS-specific tape-*.c files. - */ -DevicePropertyBase device_property_broken_gmt_online; -DevicePropertyBase device_property_fsf; -DevicePropertyBase device_property_fsf_after_filemark; -DevicePropertyBase device_property_bsf; -DevicePropertyBase device_property_fsr; -DevicePropertyBase device_property_bsr; -DevicePropertyBase device_property_eom; -DevicePropertyBase device_property_bsf_after_eom; -DevicePropertyBase device_property_nonblocking_open; -DevicePropertyBase device_property_final_filemarks; -DevicePropertyBase device_property_read_buffer_size; /* old name for READ_BLOCK_SIZE */ +/* returns a fileno like tape_fileno */ +gint tape_eod(int fd); -void tape_device_register(void); +gboolean tape_weof(int fd, guint8 count); +gboolean tape_setcompression(int fd, gboolean on); + +gboolean tape_offl(int fd); + +DeviceStatusFlags tape_is_tape_device(int fd); +DeviceStatusFlags tape_is_ready(int fd, TapeDevice *t_self); #define tape_device_read_size(self) \ (((TapeDevice *)(self))->private->read_block_size? \ ((TapeDevice *)(self))->private->read_block_size : ((Device *)(self))->block_size) +/* + * Our device-specific properties. + */ + +#define PROPERTY_BROKEN_GMT_ONLINE (device_property_broken_gmt_online.ID) +#define PROPERTY_FSF (device_property_fsf.ID) +#define PROPERTY_FSF_AFTER_FILEMARK (device_property_fsf_after_filemark.ID) +#define PROPERTY_BSF (device_property_bsf.ID) +#define PROPERTY_FSR (device_property_fsr.ID) +#define PROPERTY_BSR (device_property_bsr.ID) +#define PROPERTY_EOM (device_property_eom.ID) +#define PROPERTY_BSF_AFTER_EOM (device_property_bsf_after_eom.ID) +#define PROPERTY_NONBLOCKING_OPEN (device_property_nonblocking_open.ID) +#define PROPERTY_FINAL_FILEMARKS (device_property_final_filemarks.ID) + +static DevicePropertyBase device_property_broken_gmt_online; +static DevicePropertyBase device_property_fsf; +static DevicePropertyBase device_property_fsf_after_filemark; +static DevicePropertyBase device_property_bsf; +static DevicePropertyBase device_property_fsr; +static DevicePropertyBase device_property_bsr; +static DevicePropertyBase device_property_eom; +static DevicePropertyBase device_property_bsf_after_eom; +static DevicePropertyBase device_property_nonblocking_open; +static DevicePropertyBase device_property_final_filemarks; +static DevicePropertyBase device_property_read_buffer_size; /* old name for READ_BLOCK_SIZE */ + /* here are local prototypes */ static void tape_device_init (TapeDevice * o); static void tape_device_class_init (TapeDeviceClass * c); @@ -164,6 +263,7 @@ tape_device_init (TapeDevice * self) { self->fsr = FALSE; self->bsr = FALSE; self->eom = FALSE; + self->leom = FALSE; self->bsf_after_eom = FALSE; g_value_init(&response, G_TYPE_BOOLEAN); @@ -182,6 +282,8 @@ tape_device_init (TapeDevice * self) { &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); device_set_simple_property(d_self, PROPERTY_EOM, &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); + device_set_simple_property(d_self, PROPERTY_LEOM, + &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); device_set_simple_property(d_self, PROPERTY_BSF_AFTER_EOM, &response, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); @@ -669,84 +771,68 @@ static int try_open_tape_device(TapeDevice * self, char * device_filename) { } static void -tape_device_open_device (Device * d_self, char * device_name, +tape_device_open_device (Device * dself, char * device_name, char * device_type, char * device_node) { TapeDevice * self; + GValue val; - self = TAPE_DEVICE(d_self); + self = TAPE_DEVICE(dself); self->fd = -1; self->private->device_filename = stralloc(device_node); - /* Get tape drive/OS info */ - tape_device_detect_capabilities(self); - - /* Chain up */ - if (parent_class->open_device) { - parent_class->open_device(d_self, device_name, device_type, device_node); - } -} - -void -tape_device_set_capabilities(TapeDevice *self, - gboolean fsf, PropertySurety fsf_surety, PropertySource fsf_source, - gboolean fsf_after_filemark, PropertySurety faf_surety, PropertySource faf_source, - gboolean bsf, PropertySurety bsf_surety, PropertySource bsf_source, - gboolean fsr, PropertySurety fsr_surety, PropertySource fsr_source, - gboolean bsr, PropertySurety bsr_surety, PropertySource bsr_source, - gboolean eom, PropertySurety eom_surety, PropertySource eom_source, - gboolean bsf_after_eom, PropertySurety bae_surety, PropertySource bae_source, - guint final_filemarks, PropertySurety ff_surety, PropertySource ff_source) -{ - Device *dself = DEVICE(self); - GValue val; - - /* this function is called by tape_device_detect_capabilities, and basically - * exists to take care of the GValue mechanics in one place */ - - g_assert(final_filemarks == 1 || final_filemarks == 2); - + /* Set tape drive/OS info */ bzero(&val, sizeof(val)); g_value_init(&val, G_TYPE_BOOLEAN); - self->fsf = fsf; - g_value_set_boolean(&val, fsf); - device_set_simple_property(dself, PROPERTY_FSF, &val, fsf_surety, fsf_source); + self->fsf = TRUE; + g_value_set_boolean(&val, self->fsf); + device_set_simple_property(dself, PROPERTY_FSF, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); + + self->fsf_after_filemark = DEFAULT_FSF_AFTER_FILEMARK; + g_value_set_boolean(&val, self->fsf_after_filemark); + device_set_simple_property(dself, PROPERTY_FSF_AFTER_FILEMARK, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); - self->fsf_after_filemark = fsf_after_filemark; - g_value_set_boolean(&val, fsf_after_filemark); - device_set_simple_property(dself, PROPERTY_FSF_AFTER_FILEMARK, &val, faf_surety, faf_source); + self->bsf = TRUE; + g_value_set_boolean(&val, self->bsf); + device_set_simple_property(dself, PROPERTY_BSF, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); - self->bsf = bsf; - g_value_set_boolean(&val, bsf); - device_set_simple_property(dself, PROPERTY_BSF, &val, bsf_surety, bsf_source); + self->fsr = TRUE; + g_value_set_boolean(&val, self->fsr); + device_set_simple_property(dself, PROPERTY_FSR, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); - self->fsr = fsr; - g_value_set_boolean(&val, fsr); - device_set_simple_property(dself, PROPERTY_FSR, &val, fsr_surety, fsr_source); + self->bsr = TRUE; + g_value_set_boolean(&val, self->bsr); + device_set_simple_property(dself, PROPERTY_BSR, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); - self->bsr = bsr; - g_value_set_boolean(&val, bsr); - device_set_simple_property(dself, PROPERTY_BSR, &val, bsr_surety, bsr_source); + self->eom = TRUE; + g_value_set_boolean(&val, self->eom); + device_set_simple_property(dself, PROPERTY_EOM, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); - self->eom = eom; - g_value_set_boolean(&val, eom); - device_set_simple_property(dself, PROPERTY_EOM, &val, eom_surety, eom_source); + self->leom = FALSE; + g_value_set_boolean(&val, self->leom); + device_set_simple_property(dself, PROPERTY_LEOM, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); - self->bsf_after_eom = bsf_after_eom; - g_value_set_boolean(&val, bsf_after_eom); - device_set_simple_property(dself, PROPERTY_BSF_AFTER_EOM, &val, bae_surety, bae_source); + self->bsf_after_eom = FALSE; + g_value_set_boolean(&val, self->bsf_after_eom); + device_set_simple_property(dself, PROPERTY_BSF_AFTER_EOM, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); g_value_unset(&val); g_value_init(&val, G_TYPE_UINT); - self->final_filemarks = final_filemarks; - g_value_set_uint(&val, final_filemarks); - device_set_simple_property(dself, PROPERTY_FINAL_FILEMARKS, &val, ff_surety, ff_source); + self->final_filemarks = 2; + g_value_set_uint(&val, self->final_filemarks); + device_set_simple_property(dself, PROPERTY_FINAL_FILEMARKS, &val, PROPERTY_SURETY_BAD, PROPERTY_SOURCE_DEFAULT); g_value_unset(&val); + + /* Chain up */ + if (parent_class->open_device) { + parent_class->open_device(dself, device_name, device_type, device_node); + } } + static DeviceStatusFlags tape_device_read_label(Device * dself) { TapeDevice * self; char * header_buffer; @@ -765,9 +851,6 @@ static DeviceStatusFlags tape_device_read_label(Device * dself) { if (device_in_error(self)) return dself->status; - header = dself->volume_header = g_new(dumpfile_t, 1); - fh_init(header); - if (self->fd == -1) { self->fd = try_open_tape_device(self, self->private->device_filename); /* if the open failed, then try_open_tape_device already set the @@ -799,12 +882,17 @@ static DeviceStatusFlags tape_device_read_label(Device * dself) { msg = stralloc(_("no data")); new_status = (DEVICE_STATUS_VOLUME_ERROR | DEVICE_STATUS_VOLUME_UNLABELED); + header = dself->volume_header = g_new(dumpfile_t, 1); + fh_init(header); break; case RESULT_SMALL_BUFFER: msg = stralloc(_("block size too small")); new_status = (DEVICE_STATUS_DEVICE_ERROR | DEVICE_STATUS_VOLUME_ERROR); + header = dself->volume_header = g_new(dumpfile_t, 1); + fh_init(header); + header->type = F_WEIRD; break; default: @@ -823,6 +911,9 @@ static DeviceStatusFlags tape_device_read_label(Device * dself) { return dself->status; } + header = dself->volume_header = g_new(dumpfile_t, 1); + fh_init(header); + parse_file_header(header_buffer, header, buffer_len); amfree(header_buffer); if (header->type != F_TAPESTART) { @@ -1130,8 +1221,6 @@ static gboolean tape_device_start_file(Device * d_self, char * amanda_header; char *msg = NULL; - d_self->is_eom = FALSE; - self = TAPE_DEVICE(d_self); g_assert(self->fd >= 0); @@ -1429,7 +1518,8 @@ tape_device_finish (Device * d_self) { self = TAPE_DEVICE(d_self); - if (device_in_error(self)) return FALSE; + if (device_in_error(self)) + goto finish_error; /* if we're already in ACCESS_NULL, then there are no filemarks or anything * to worry about, but we need to release the kernel device */ @@ -1442,7 +1532,7 @@ tape_device_finish (Device * d_self) { /* Polish off this file, if relevant. */ if (d_self->in_file && IS_WRITABLE_ACCESS_MODE(d_self->access_mode)) { if (!device_finish_file(d_self)) - return FALSE; + goto finish_error; } /* Straighten out the filemarks. We already wrote one in finish_file, and @@ -1464,7 +1554,7 @@ tape_device_finish (Device * d_self) { device_set_error(d_self, stralloc(_("Amanda file header won't fit in a single block!")), DEVICE_STATUS_DEVICE_ERROR); - return FALSE; + goto finish_error; } result = tape_device_robust_write(self, header, d_self->block_size, &msg); @@ -1475,7 +1565,7 @@ tape_device_finish (Device * d_self) { DEVICE_STATUS_DEVICE_ERROR); amfree(header); amfree(msg); - return FALSE; + goto finish_error; } amfree(header); } @@ -1485,7 +1575,7 @@ tape_device_finish (Device * d_self) { device_set_error(d_self, vstrallocf(_("Couldn't rewind device to finish: %s"), strerror(errno)), DEVICE_STATUS_DEVICE_ERROR); - return FALSE; + goto finish_error; } d_self->is_eof = FALSE; @@ -1496,6 +1586,15 @@ tape_device_finish (Device * d_self) { self->fd = -1; return TRUE; + +finish_error: + d_self->access_mode = ACCESS_NULL; + + /* release the kernel's device */ + robust_close(self->fd); + self->fd = -1; + + return FALSE; } /* Works just like read(), except for the following: @@ -1593,6 +1692,7 @@ static IoResult tape_device_robust_write (TapeDevice * self, void * buf, int count, char **errmsg) { Device * d_self; int result; + gboolean retry = FALSE; d_self = (Device*)self; @@ -1601,17 +1701,51 @@ tape_device_robust_write (TapeDevice * self, void * buf, int count, char **errms for (;;) { result = write(self->fd, buf, count); - if (result == count) { - /* Success. */ - - self->private->write_count ++; + /* Success. */ + if (result == count) return RESULT_SUCCESS; - } else if (result >= 0) { - /* write() returned a short count. This should not happen. */ - *errmsg = g_strdup_printf("Mysterious short write on tape device: Tried %d, got %d", - count, result); + + if (result > 0) { + /* write() returned a short count. This should not happen if the block sizes + * are properly aligned. */ + *errmsg = g_strdup_printf("Short write on tape device: Tried %d, got %d. Is " + "the drive using a block size smaller than %d bytes?", + count, result, count); return RESULT_ERROR; - } else if (0 + } + + /* Detect LEOM (early warning) and handle properly + * + * FreeBSD: 0-length write; next write will succeed + * http://lists.freebsd.org/pipermail/freebsd-scsi/2010-June/004414.html + * + * Solaris: 0-length write; next write will succeed + * (from Matthew Jacob on FreeBSD thread) + * + * Linux: -1/ENOSPC; next write will succeed + * http://www.mjmwired.net/kernel/Documentation/scsi/st.txt + * + * HP/UX: -1/ENOSPC; next write will succeed + * http://www.adssasia.com/Manual/IBM%203581%20tape%20autoloader.pdf + */ + if (result == 0 +#ifdef ENOSPC + || (result < 0 && errno == ENOSPC) +#endif + ) { + /* if we've retried once already, then we're probably really out of space */ + if (retry) + return RESULT_NO_SPACE; + retry = TRUE; + d_self->is_eom = TRUE; + + g_debug("empty write to tape; treating as LEOM early warning and retrying"); + continue; + } + + /* at this point result < 0, so an error occurred - sort out what */ + + if (0 #ifdef EAGAIN || errno == EAGAIN #endif @@ -1839,3 +1973,184 @@ tape_device_factory (char * device_name, char * device_type, char * device_node) device_open_device(rval, device_name, device_type, device_node); return rval; } + +/* + * Tape Operations using the POSIX interface + */ + +/* Having one name for every operation would be too easy. */ +#if !defined(MTCOMPRESSION) && defined(MTCOMP) +# define MTCOMPRESSION MTCOMP +#endif + +#if !defined(MTSETBLK) && defined(MTSETBSIZ) +# define MTSETBLK MTSETBSIZ +#endif + +#if !defined(MTEOM) && defined(MTEOD) +# define MTEOM MTEOD +#endif + +gboolean tape_rewind(int fd) { + int count = 5; + time_t stop_time; + + /* We will retry this for up to 30 seconds or 5 retries, + whichever is less, because some hardware/software combinations + (notably EXB-8200 on FreeBSD) can fail to rewind. */ + stop_time = time(NULL) + 30; + + while (--count >= 0 && time(NULL) < stop_time) { + struct mtop mt; + mt.mt_op = MTREW; + mt.mt_count = 1; + + if (0 == ioctl(fd, MTIOCTOP, &mt)) + return TRUE; + + sleep(3); + } + + return FALSE; +} + +gboolean tape_fsf(int fd, guint count) { + struct mtop mt; + mt.mt_op = MTFSF; + mt.mt_count = count; + return 0 == ioctl(fd, MTIOCTOP, &mt); +} + +gboolean tape_bsf(int fd, guint count) { + struct mtop mt; + mt.mt_op = MTBSF; + mt.mt_count = count; + return 0 == ioctl(fd, MTIOCTOP, &mt); +} + +gboolean tape_fsr(int fd, guint count) { + struct mtop mt; + mt.mt_op = MTFSR; + mt.mt_count = count; + return 0 == ioctl(fd, MTIOCTOP, &mt); +} + +gboolean tape_bsr(int fd, guint count) { + struct mtop mt; + mt.mt_op = MTBSR; + mt.mt_count = count; + return 0 == ioctl(fd, MTIOCTOP, &mt); +} + +gint tape_fileno(int fd) { + struct mtget get; + + if (0 != ioctl(fd, MTIOCGET, &get)) + return TAPE_POSITION_UNKNOWN; + if (get.mt_fileno < 0) + return TAPE_POSITION_UNKNOWN; + else + return get.mt_fileno; +} + +gint tape_eod(int fd) { + struct mtop mt; + struct mtget get; + mt.mt_op = MTEOM; + mt.mt_count = 1; + if (0 != ioctl(fd, MTIOCTOP, &mt)) + return TAPE_OP_ERROR; + + /* Ignored result. This is just to flush buffers. */ + mt.mt_op = MTNOP; + ioctl(fd, MTIOCTOP, &mt); + + if (0 != ioctl(fd, MTIOCGET, &get)) + return TAPE_POSITION_UNKNOWN; + if (get.mt_fileno < 0) + return TAPE_POSITION_UNKNOWN; + else + return get.mt_fileno; +} + +gboolean tape_weof(int fd, guint8 count) { + struct mtop mt; + mt.mt_op = MTWEOF; + mt.mt_count = count; + return 0 == ioctl(fd, MTIOCTOP, &mt); +} + +gboolean tape_setcompression(int fd G_GNUC_UNUSED, + gboolean on G_GNUC_UNUSED) { +#ifdef MTCOMPRESSION + struct mtop mt; + mt.mt_op = MTCOMPRESSION; + mt.mt_count = on; + return 0 == ioctl(fd, MTIOCTOP, &mt); +#else + return 0; +#endif +} + +gboolean tape_offl(int fd) { + struct mtop mt; + int safe_errno; + + mt.mt_op = MTOFFL; + mt.mt_count = 1; + if (0 == ioctl(fd, MTIOCTOP, &mt)) + return TRUE; + + safe_errno = errno; + g_debug("tape_off: ioctl(MTIOCTOP/MTOFFL) failed: %s", strerror(errno)); + errno = safe_errno; + + return FALSE; +} + +DeviceStatusFlags tape_is_tape_device(int fd) { + struct mtop mt; + mt.mt_op = MTNOP; + mt.mt_count = 1; + if (0 == ioctl(fd, MTIOCTOP, &mt)) { + return DEVICE_STATUS_SUCCESS; +#ifdef ENOMEDIUM + } else if (errno == ENOMEDIUM) { + return DEVICE_STATUS_VOLUME_MISSING; +#endif + } else { + g_debug("tape_is_tape_device: ioctl(MTIOCTOP/MTNOP) failed: %s", + strerror(errno)); + if (errno == EIO) { + /* some devices return EIO while the drive is busy loading */ + return DEVICE_STATUS_DEVICE_ERROR|DEVICE_STATUS_DEVICE_BUSY; + } else { + return DEVICE_STATUS_DEVICE_ERROR; + } + } +} + +DeviceStatusFlags tape_is_ready(int fd, TapeDevice *t_self G_GNUC_UNUSED) { + struct mtget get; + if (0 == ioctl(fd, MTIOCGET, &get)) { +#if defined(GMT_ONLINE) || defined(GMT_DR_OPEN) + if (1 +#ifdef GMT_ONLINE + && (t_self->broken_gmt_online || GMT_ONLINE(get.mt_gstat)) +#endif +#ifdef GMT_DR_OPEN + && !GMT_DR_OPEN(get.mt_gstat) +#endif + ) { + return DEVICE_STATUS_SUCCESS; + } else { + return DEVICE_STATUS_VOLUME_MISSING; + } +#else /* Neither macro is defined. */ + return DEVICE_STATUS_SUCCESS; +#endif + } else { + return DEVICE_STATUS_VOLUME_ERROR; + } +} +