Imported Upstream version 3.1.0
[debian/amanda] / ndmp-src / amndma_tape_simulator.c
diff --git a/ndmp-src/amndma_tape_simulator.c b/ndmp-src/amndma_tape_simulator.c
new file mode 100644 (file)
index 0000000..6e665db
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 1998,1999,2000
+ *     Traakan, Inc., Los Altos, CA
+ *     All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice unmodified, this list of conditions, and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Project:  NDMJOB
+ * Ident:    $Id: $
+ *
+ * Description:
+ *
+ */
+
+
+#include "ndmagents.h"
+
+
+#ifndef NDMOS_OPTION_NO_TAPE_AGENT
+
+
+int    simu_back_one (struct ndm_session *sess, int over_file_mark);
+int    simu_forw_one (struct ndm_session *sess, int over_file_mark);
+int    simu_flush_weof (struct ndm_session *sess);
+
+
+#ifdef NDMOS_OPTION_TAPE_SIMULATOR
+
+#define SIMU_GAP_MAGIC         0x0BEEFEE0
+#define SIMU_GAP_RT_(a,b,c,d) ((a<<0)+(b<<8)+(c<<16)+(d<<24))
+#define SIMU_GAP_RT_BOT                SIMU_GAP_RT_('B','O','T','_')
+#define SIMU_GAP_RT_DATA       SIMU_GAP_RT_('D','A','T','A')
+#define SIMU_GAP_RT_FILE       SIMU_GAP_RT_('F','I','L','E')
+#define SIMU_GAP_RT_EOT                SIMU_GAP_RT_('E','O','T','_')
+
+
+
+int
+ndmos_tape_initialize (struct ndm_session *sess)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+
+       ta->tape_fd = -1;
+       NDMOS_MACRO_ZEROFILL (&ta->tape_state);
+       ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
+       ta->tape_state.state = NDMP9_TAPE_STATE_IDLE;
+
+       return 0;
+}
+
+ndmp9_error
+ndmos_tape_open (struct ndm_session *sess, char *drive_name, int will_write)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       struct stat             st;
+       int                     read_only, omode;
+       int                     fd;
+
+       if (ta->tape_fd >= 0) {
+               return NDMP9_DEVICE_OPENED_ERR;
+       }
+
+       if (*drive_name >= '0' && *drive_name <= '9') {
+               fd = atoi(drive_name);
+               goto skip_header_check;
+       }
+
+       if (stat (drive_name, &st) < 0) {
+               return NDMP9_NO_DEVICE_ERR;
+       }
+
+       read_only = (st.st_mode & 0222) == 0;
+
+       if (!will_write) {
+               omode = 0;
+       } else {
+               if (read_only)
+                       return NDMP9_WRITE_PROTECT_ERR;
+               omode = 2;              /* ndmp_write means read/write */
+       }
+
+       fd = open (drive_name, omode);
+       if (fd < 0) {
+               return NDMP9_PERMISSION_ERR;
+       }
+
+       if (st.st_size == 0) {
+               if (will_write) {
+                       lseek (fd, (off_t)0, 0);
+               } else {
+                       goto skip_header_check;
+               }
+       }
+
+  skip_header_check:
+       ta->tape_fd = fd;
+       NDMOS_API_BZERO (ta->drive_name, sizeof ta->drive_name);
+       strcpy (ta->drive_name, drive_name);
+       bzero (&ta->tape_state, sizeof ta->tape_state);
+       ta->tape_state.error = NDMP9_NO_ERR;
+       ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
+       ta->tape_state.open_mode =
+               will_write ? NDMP9_TAPE_RDWR_MODE : NDMP9_TAPE_READ_MODE;
+       ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
+       ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
+       ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
+       ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
+       ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
+       ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
+
+       return NDMP9_NO_ERR;
+}
+
+ndmp9_error
+ndmos_tape_close (struct ndm_session *sess)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+
+       if (ta->tape_fd < 0) {
+               return NDMP9_DEV_NOT_OPEN_ERR;
+       }
+
+       simu_flush_weof(sess);
+
+#if 0
+       u_long                  resid;
+       ndmos_tape_mtio (sess, NDMP9_MTIO_REW, 1, &resid);
+#endif
+
+       close (ta->tape_fd);
+       ta->tape_fd = -1;
+
+       ndmos_tape_initialize (sess);
+
+       return NDMP9_NO_ERR;
+}
+
+void
+ndmos_tape_sync_state (struct ndm_session *sess)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+
+       if (ta->tape_fd < 0) {
+               ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
+               ta->tape_state.state = NDMP9_TAPE_STATE_IDLE;
+               ta->tape_state.file_num.valid = NDMP9_VALIDITY_INVALID;
+               ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_INVALID;
+               ta->tape_state.block_size.valid = NDMP9_VALIDITY_INVALID;
+               ta->tape_state.blockno.valid = NDMP9_VALIDITY_INVALID;
+               ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
+               ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
+       } else {
+               ta->tape_state.error = NDMP9_NO_ERR;
+               if (ta->mover_state.state == NDMP9_MOVER_STATE_ACTIVE)
+                       ta->tape_state.state = NDMP9_TAPE_STATE_MOVER;
+               else
+                       ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
+               ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
+               ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
+               ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
+               ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
+               ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
+               ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
+       }
+
+       return;
+}
+
+int
+simu_back_one (struct ndm_session *sess, int over_file_mark)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       off_t                   cur_pos;
+
+       cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
+       lseek (ta->tape_fd, 0, 0);
+return 0;
+}
+
+int
+simu_forw_one (struct ndm_session *sess, int over_file_mark)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       off_t                   cur_pos;
+
+       cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
+return 0;
+
+}
+
+int
+simu_flush_weof (struct ndm_session *sess)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+
+       if (ta->weof_on_close) {
+               /* best effort */
+               ndmos_tape_wfm (sess);
+       }
+       return 0;
+}
+
+
+ndmp9_error
+ndmos_tape_mtio (struct ndm_session *sess,
+  ndmp9_tape_mtio_op op, u_long count, u_long *resid)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       int                     rc;
+
+       *resid = 0;
+
+       if (ta->tape_fd < 0) {
+               return NDMP9_DEV_NOT_OPEN_ERR;
+       }
+
+       
+       /* audit for valid op and for tape mode */
+       switch (op) {
+       case NDMP9_MTIO_FSF:
+               return NDMP9_NO_ERR;
+               while (*resid > 0) {
+                       simu_flush_weof(sess);
+                       rc = simu_forw_one (sess, 1);
+                       if (rc < 0)
+                               return NDMP9_IO_ERR;
+                       if (rc == 0)
+                               break;
+                       if (rc == SIMU_GAP_RT_FILE)
+                               *resid -= 1;
+               }
+               break;
+
+       case NDMP9_MTIO_BSF:
+               return NDMP9_NO_ERR;
+               while (*resid > 0) {
+                       simu_flush_weof(sess);
+                       rc = simu_back_one (sess, 1);
+                       if (rc < 0)
+                               return NDMP9_IO_ERR;
+                       if (rc == 0)
+                               break;
+                       if (rc == SIMU_GAP_RT_FILE)
+                               *resid -= 1;
+               }
+               break;
+
+       case NDMP9_MTIO_FSR:
+               return NDMP9_NO_ERR;
+               while (*resid > 0) {
+                       simu_flush_weof(sess);
+                       rc = simu_forw_one (sess, 0);
+                       if (rc < 0)
+                               return NDMP9_IO_ERR;
+                       if (rc == 0)
+                               break;
+                       *resid -= 1;
+               }
+               break;
+
+       case NDMP9_MTIO_BSR:
+               return NDMP9_NO_ERR;
+               while (*resid > 0) {
+                       simu_flush_weof(sess);
+                       rc = simu_back_one (sess, 0);
+                       if (rc < 0)
+                               return NDMP9_IO_ERR;
+                       if (rc == 0)
+                               break;
+                       *resid -= 1;
+               }
+               break;
+
+       case NDMP9_MTIO_REW:
+               simu_flush_weof(sess);
+               *resid = 0;
+               ta->tape_state.file_num.value = 0;
+               ta->tape_state.blockno.value = 0;
+               //lseek (ta->tape_fd, (off_t)(sizeof (struct simu_gap)), 0);
+               lseek (ta->tape_fd, (off_t)0, 0);
+               ndmalogf(sess, 0, 7, "NDMP9_MTIO_REW");
+               sleep(1);
+               break;
+
+       case NDMP9_MTIO_OFF:
+               return NDMP9_NO_ERR;
+               simu_flush_weof(sess);
+               /* Hmmm. */
+               break;
+
+       case NDMP9_MTIO_EOF:            /* should be "WFM" write-file-mark */
+               return NDMP9_NO_ERR;
+               if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
+                       return NDMP9_PERMISSION_ERR;
+               }
+               while (*resid > 0) {
+                       ndmp9_error     err;
+
+                       err = ndmos_tape_wfm (sess);
+                       if (err != NDMP9_NO_ERR)
+                               return err;
+
+                       *resid -= 1;
+               }
+               break;
+
+       default:
+               return NDMP9_ILLEGAL_ARGS_ERR;
+       }
+
+       return NDMP9_NO_ERR;
+}
+
+ndmp9_error
+ndmos_tape_write (struct ndm_session *sess,
+  char *buf, u_long count, u_long *done_count)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       off_t                   cur_pos;
+       ndmp9_error             err;
+       u_long                  prev_size;
+       int                     rc;
+
+       if (ta->tape_fd < 0) {
+               return NDMP9_DEV_NOT_OPEN_ERR;
+       }
+
+       if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
+               return NDMP9_PERMISSION_ERR;
+       }
+
+       if (count == 0) {
+               /*
+                * NDMPv4 clarification -- a tape read or write with
+                * a count==0 is a no-op. This is undoubtedly influenced
+                * by the SCSI Sequential Access specification which
+                * says much the same thing.
+                */
+               *done_count = 0;
+               return NDMP9_NO_ERR;
+       }
+
+       cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
+       lseek (ta->tape_fd, cur_pos, 0);
+
+       if ((u_long)full_write (ta->tape_fd, buf, count) == count) {
+               cur_pos += count;
+
+               prev_size = count;
+
+               ta->tape_state.blockno.value++;
+
+               *done_count = count;
+
+               err = NDMP9_NO_ERR;
+       } else {
+               ndmalogf(sess, 0, 7, "full_write not %d", count);
+               err = NDMP9_IO_ERR;
+       }
+
+       /* error ignored for pipe file descriptor */
+       rc = ftruncate (ta->tape_fd, cur_pos);
+
+       lseek (ta->tape_fd, cur_pos, 0);
+
+       ta->weof_on_close = 1;
+
+       return err;
+}
+
+ndmp9_error
+ndmos_tape_wfm (struct ndm_session *sess)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       off_t                   cur_pos;
+       ndmp9_error             err;
+       int                     rc;
+
+       ta->weof_on_close = 0;
+
+       if (ta->tape_fd < 0) {
+               return NDMP9_DEV_NOT_OPEN_ERR;
+       }
+
+       if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
+               return NDMP9_PERMISSION_ERR;
+       }
+
+       cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
+
+       lseek (ta->tape_fd, cur_pos, 0);
+       err = NDMP9_NO_ERR;
+
+       /* error ignored for pipe file descriptor */
+       rc = ftruncate (ta->tape_fd, cur_pos);
+
+       lseek (ta->tape_fd, cur_pos, 0);
+
+       return err;
+}
+
+ndmp9_error
+ndmos_tape_read (struct ndm_session *sess,
+  char *buf, u_long count, u_long *done_count)
+{
+       struct ndm_tape_agent * ta = &sess->tape_acb;
+       int                     rc;
+       unsigned        nb;
+
+       if (ta->tape_fd < 0) {
+               return NDMP9_DEV_NOT_OPEN_ERR;
+       }
+
+       if (count == 0) {
+               /*
+                * NDMPv4 clarification -- a tape read or write with
+                * a count==0 is a no-op. This is undoubtedly influenced
+                * by the SCSI Sequential Access specification which
+                * says much the same thing.
+                */
+
+               *done_count = 0;
+               return NDMP9_NO_ERR;
+       }
+
+       nb = count;
+
+       rc = read (ta->tape_fd, buf, nb);
+       if (rc < 0) {
+               return NDMP9_IO_ERR;
+       }
+       ta->tape_state.blockno.value++;
+
+       *done_count = rc;
+
+       if (rc == 0) {
+               return NDMP9_EOF_ERR;
+       }
+       return NDMP9_NO_ERR;
+}
+
+#endif /* NDMOS_OPTION_TAPE_SIMULATOR */
+
+#endif /* !NDMOS_OPTION_NO_TAPE_AGENT */