/*
* 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);
g_strlcpy (ta->drive_name, drive_name, sizeof ta->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;
break;
case NDMP9_MTIO_BSF:
return NDMP9_NO_ERR;
break;
case NDMP9_MTIO_FSR:
return NDMP9_NO_ERR;
break;
case NDMP9_MTIO_BSR:
return NDMP9_NO_ERR;
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;
break;
case NDMP9_MTIO_EOF: /* should be "WFM" write-file-mark */
return NDMP9_NO_ERR;
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;
gsize rc, nb;
int read_error;
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_fully(ta->tape_fd, buf, nb, &read_error);
if (read_error) {
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 */