Blame ndmp-src/ndma_tape_simulator.c

Packit Service 392537
/*
Packit Service 392537
 * Copyright (c) 1998,1999,2000
Packit Service 392537
 *	Traakan, Inc., Los Altos, CA
Packit Service 392537
 *	All rights reserved.
Packit Service 392537
 *
Packit Service 392537
 * Redistribution and use in source and binary forms, with or without
Packit Service 392537
 * modification, are permitted provided that the following conditions
Packit Service 392537
 * are met:
Packit Service 392537
 * 1. Redistributions of source code must retain the above copyright
Packit Service 392537
 *    notice unmodified, this list of conditions, and the following
Packit Service 392537
 *    disclaimer.
Packit Service 392537
 * 2. Redistributions in binary form must reproduce the above copyright
Packit Service 392537
 *    notice, this list of conditions and the following disclaimer in the
Packit Service 392537
 *    documentation and/or other materials provided with the distribution.
Packit Service 392537
 *
Packit Service 392537
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
Packit Service 392537
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
Packit Service 392537
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
Packit Service 392537
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
Packit Service 392537
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
Packit Service 392537
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
Packit Service 392537
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
Packit Service 392537
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
Packit Service 392537
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
Packit Service 392537
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
Packit Service 392537
 * SUCH DAMAGE.
Packit Service 392537
 */
Packit Service 392537
Packit Service 392537
/*
Packit Service 392537
 * Project:  NDMJOB
Packit Service 392537
 * Ident:    $Id: $
Packit Service 392537
 *
Packit Service 392537
 * Description:
Packit Service 392537
 *
Packit Service 392537
 */
Packit Service 392537
Packit Service 392537
Packit Service 392537
#include "ndmagents.h"
Packit Service 392537
Packit Service 392537
Packit Service 392537
#ifndef NDMOS_OPTION_NO_TAPE_AGENT
Packit Service 392537
Packit Service 392537
Packit Service 392537
int	simu_back_one (struct ndm_session *sess, int over_file_mark);
Packit Service 392537
int	simu_forw_one (struct ndm_session *sess, int over_file_mark);
Packit Service 392537
int	simu_flush_weof (struct ndm_session *sess);
Packit Service 392537
Packit Service 392537
Packit Service 392537
#ifdef NDMOS_OPTION_TAPE_SIMULATOR
Packit Service 392537
Packit Service 392537
struct simu_gap {
Packit Service 392537
	u_long		magic;
Packit Service 392537
	u_long		rectype;
Packit Service 392537
	u_long		prev_size;
Packit Service 392537
	u_long		size;
Packit Service 392537
};
Packit Service 392537
Packit Service 392537
#define SIMU_GAP_MAGIC		0x0BEEFEE0
Packit Service 392537
#define SIMU_GAP_RT_(a,b,c,d) ((a<<0)+(b<<8)+(c<<16)+(d<<24))
Packit Service 392537
#define SIMU_GAP_RT_BOT		SIMU_GAP_RT_('B','O','T','_')
Packit Service 392537
#define SIMU_GAP_RT_DATA	SIMU_GAP_RT_('D','A','T','A')
Packit Service 392537
#define SIMU_GAP_RT_FILE	SIMU_GAP_RT_('F','I','L','E')
Packit Service 392537
#define SIMU_GAP_RT_EOT		SIMU_GAP_RT_('E','O','T','_')
Packit Service 392537
Packit Service 392537
/* send logical EOM with a bit less than 2 32k blocks left (due to SIMU_GAPs) */
Packit Service 392537
#define TAPE_SIM_LOGICAL_EOM	32768*2
Packit Service 392537
Packit Service 392537
/* we sneak a peek at this global variable - probably not the best way, but
Packit Service 392537
 * it works */
Packit Service 392537
extern off_t o_tape_limit;
Packit Service 392537
Packit Service 392537
int
Packit Service 392537
ndmos_tape_initialize (struct ndm_session *sess)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
Packit Service 392537
	ta->tape_fd = -1;
Packit Service 392537
	NDMOS_MACRO_ZEROFILL (&ta->tape_state);
Packit Service 392537
	ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
	ta->tape_state.state = NDMP9_TAPE_STATE_IDLE;
Packit Service 392537
Packit Service 392537
	return 0;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
static int
Packit Service 392537
touch_tape_lockfile(char *drive_name)
Packit Service 392537
{
Packit Service 392537
    char *lockfile_name;
Packit Service 392537
    int fd;
Packit Service 392537
Packit Service 392537
    lockfile_name = g_strdup_printf("%s.lck", drive_name);
Packit Service 392537
    if ((fd = open(lockfile_name, O_CREAT|O_EXCL, 0666)) < 0) {
Packit Service 392537
	g_free(lockfile_name);
Packit Service 392537
	return -1;
Packit Service 392537
    }
Packit Service 392537
Packit Service 392537
    close(fd);
Packit Service 392537
    g_free(lockfile_name);
Packit Service 392537
    return 0;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
static void
Packit Service 392537
unlink_tape_lockfile(char *drive_name)
Packit Service 392537
{
Packit Service 392537
    char *lockfile_name;
Packit Service 392537
Packit Service 392537
    lockfile_name = g_strdup_printf("%s.lck", drive_name);
Packit Service 392537
    unlink(lockfile_name);
Packit Service 392537
    g_free(lockfile_name);
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
ndmp9_error
Packit Service 392537
ndmos_tape_open (struct ndm_session *sess, char *drive_name, int will_write)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	struct simu_gap		gap;
Packit Service 392537
	struct stat		st;
Packit Service 392537
	int			read_only, omode;
Packit Service 392537
	int			rc, fd;
Packit Service 392537
	char			*pos_symlink_name;
Packit Service 392537
	char			pos_buf[32];
Packit Service 392537
	off_t			pos = -1;
Packit Service 392537
Packit Service 392537
        if (ta->tape_fd >= 0) {
Packit Service 392537
                ndma_send_logmsg(sess, NDMP9_LOG_ERROR, sess->plumb.control,
Packit Service 392537
                         "device simulator is already open");
Packit Service 392537
                return NDMP9_DEVICE_OPENED_ERR;
Packit Service 392537
        }
Packit Service 392537
Packit Service 392537
	if (stat (drive_name, &st) < 0) {
Packit Service 392537
		return NDMP9_NO_DEVICE_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	read_only = (st.st_mode & 0222) == 0;
Packit Service 392537
Packit Service 392537
	if (!will_write) {
Packit Service 392537
		omode = 0;
Packit Service 392537
	} else {
Packit Service 392537
		if (read_only)
Packit Service 392537
			return NDMP9_WRITE_PROTECT_ERR;
Packit Service 392537
		omode = 2;		/* ndmp_write means read/write */
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (touch_tape_lockfile(drive_name) < 0)
Packit Service 392537
	    return NDMP9_DEVICE_BUSY_ERR;
Packit Service 392537
Packit Service 392537
	fd = open (drive_name, omode);
Packit Service 392537
	if (fd < 0) {
Packit Service 392537
		return NDMP9_PERMISSION_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	pos_symlink_name = g_strdup_printf("%s.pos", drive_name);
Packit Service 392537
Packit Service 392537
	if (st.st_size == 0) {
Packit Service 392537
		remove (pos_symlink_name);
Packit Service 392537
		if (will_write) {
Packit Service 392537
			gap.magic = SIMU_GAP_MAGIC;
Packit Service 392537
			gap.rectype = SIMU_GAP_RT_BOT;
Packit Service 392537
			gap.size = 0;
Packit Service 392537
			gap.prev_size = 0;
Packit Service 392537
			if (write (fd, &gap, sizeof gap) < (int)sizeof gap) {
Packit Service 392537
			    close(fd);
Packit Service 392537
			    return NDMP9_IO_ERR;
Packit Service 392537
			}
Packit Service 392537
Packit Service 392537
			gap.rectype = SIMU_GAP_RT_EOT;
Packit Service 392537
			if (write (fd, &gap, sizeof gap) < (int)sizeof gap) {
Packit Service 392537
			    close(fd);
Packit Service 392537
			    return NDMP9_IO_ERR;
Packit Service 392537
			}
Packit Service 392537
			lseek (fd, (off_t)0, 0);
Packit Service 392537
		} else {
Packit Service 392537
			goto skip_header_check;
Packit Service 392537
		}
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	rc = read (fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap) {
Packit Service 392537
		close (fd);
Packit Service 392537
		return NDMP9_NO_TAPE_LOADED_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
#if 1
Packit Service 392537
	if (gap.magic != SIMU_GAP_MAGIC) {
Packit Service 392537
		close (fd);
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
#else
Packit Service 392537
	if (gap.magic != SIMU_GAP_MAGIC
Packit Service 392537
	 || gap.rectype != SIMU_GAP_RT_BOT
Packit Service 392537
	 || gap.size != 0) {
Packit Service 392537
		close (fd);
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
	rc = readlink (pos_symlink_name, pos_buf, sizeof pos_buf);
Packit Service 392537
	if (rc > 0) {
Packit Service 392537
		pos_buf[sizeof pos_buf - 1] = 0;
Packit Service 392537
		if (rc < sizeof pos_buf)
Packit Service 392537
		    pos_buf[rc] = 0;
Packit Service 392537
		pos = strtol (pos_buf, 0, 0);
Packit Service 392537
		lseek (fd, pos, 0);
Packit Service 392537
		rc = read (fd, &gap, sizeof gap);
Packit Service 392537
		if (rc == sizeof gap && gap.magic == SIMU_GAP_MAGIC) {
Packit Service 392537
		} else {
Packit Service 392537
			pos = sizeof gap;
Packit Service 392537
		}
Packit Service 392537
		lseek (fd, pos, 0);
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
  skip_header_check:
Packit Service 392537
	remove (pos_symlink_name);
Packit Service 392537
	g_free(pos_symlink_name);
Packit Service 392537
Packit Service 392537
	ta->tape_fd = fd;
Packit Service 392537
	NDMOS_API_BZERO (ta->drive_name, sizeof ta->drive_name);
Packit Service 392537
	g_strlcpy (ta->drive_name, drive_name, sizeof ta->drive_name);
Packit Service 392537
	bzero (&ta->tape_state, sizeof ta->tape_state);
Packit Service 392537
	ta->tape_state.error = NDMP9_NO_ERR;
Packit Service 392537
	ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
Packit Service 392537
	ta->tape_state.open_mode =
Packit Service 392537
		will_write ? NDMP9_TAPE_RDWR_MODE : NDMP9_TAPE_READ_MODE;
Packit Service 392537
	ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	ta->tape_state.total_space.valid = NDMP9_VALIDITY_INVALID;
Packit Service 392537
	ta->tape_state.space_remain.valid = NDMP9_VALIDITY_INVALID;
Packit Service 392537
Packit Service 392537
	ta->sent_leom = 0;
Packit Service 392537
	if (o_tape_limit) {
Packit Service 392537
	    g_assert(o_tape_limit > st.st_size);
Packit Service 392537
Packit Service 392537
	    ta->tape_state.total_space.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	    ta->tape_state.total_space.value = o_tape_limit;
Packit Service 392537
	    ta->tape_state.space_remain.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	    ta->tape_state.space_remain.value = o_tape_limit - st.st_size;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	return NDMP9_NO_ERR;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
ndmp9_error
Packit Service 392537
ndmos_tape_close (struct ndm_session *sess)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	off_t			cur_pos;
Packit Service 392537
Packit Service 392537
	/* TODO this is not called on an EOF from the DMA, so the lockfile
Packit Service 392537
	 * will remain, although the spec says the tape service should be
Packit Service 392537
	 * automatically closed */
Packit Service 392537
Packit Service 392537
	if (ta->tape_fd < 0) {
Packit Service 392537
		return NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	simu_flush_weof(sess);
Packit Service 392537
Packit Service 392537
#if 0
Packit Service 392537
	u_long			resid;
Packit Service 392537
	ndmos_tape_mtio (sess, NDMP9_MTIO_REW, 1, &resid);
Packit Service 392537
#endif
Packit Service 392537
Packit Service 392537
	cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
Packit Service 392537
	if (cur_pos != -1) {
Packit Service 392537
		char		*pos_symlink_name;
Packit Service 392537
		char		pos_buf[32];
Packit Service 392537
Packit Service 392537
		pos_symlink_name = g_strdup_printf("%s.pos", ta->drive_name);
Packit Service 392537
		sprintf (pos_buf, "%ld", (long) cur_pos);
Packit Service 392537
		if (symlink (pos_buf, pos_symlink_name) < 0) {
Packit Service 392537
		    ; /* ignore error during close */
Packit Service 392537
		}
Packit Service 392537
		g_free(pos_symlink_name);
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	close (ta->tape_fd);
Packit Service 392537
	ta->tape_fd = -1;
Packit Service 392537
Packit Service 392537
	unlink_tape_lockfile(ta->drive_name);
Packit Service 392537
Packit Service 392537
	ndmos_tape_initialize (sess);
Packit Service 392537
Packit Service 392537
	return NDMP9_NO_ERR;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
void
Packit Service 392537
ndmos_tape_sync_state (struct ndm_session *sess)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
Packit Service 392537
	if (ta->tape_fd < 0) {
Packit Service 392537
		ta->tape_state.error = NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
		ta->tape_state.state = NDMP9_TAPE_STATE_IDLE;
Packit Service 392537
		ta->tape_state.file_num.valid = NDMP9_VALIDITY_INVALID;
Packit Service 392537
		ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_INVALID;
Packit Service 392537
		ta->tape_state.block_size.valid = NDMP9_VALIDITY_INVALID;
Packit Service 392537
		ta->tape_state.blockno.valid = NDMP9_VALIDITY_INVALID;
Packit Service 392537
	} else {
Packit Service 392537
		ta->tape_state.error = NDMP9_NO_ERR;
Packit Service 392537
		if (ta->mover_state.state == NDMP9_MOVER_STATE_ACTIVE)
Packit Service 392537
			ta->tape_state.state = NDMP9_TAPE_STATE_MOVER;
Packit Service 392537
		else
Packit Service 392537
			ta->tape_state.state = NDMP9_TAPE_STATE_OPEN;
Packit Service 392537
		ta->tape_state.file_num.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
		ta->tape_state.soft_errors.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
		ta->tape_state.block_size.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
		ta->tape_state.blockno.valid = NDMP9_VALIDITY_VALID;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	return;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
int
Packit Service 392537
simu_back_one (struct ndm_session *sess, int over_file_mark)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	struct simu_gap		gap;
Packit Service 392537
	off_t			cur_pos;
Packit Service 392537
	off_t			new_pos;
Packit Service 392537
	int			rc;
Packit Service 392537
Packit Service 392537
	cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
Packit Service 392537
Packit Service 392537
	rc = read (ta->tape_fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap || gap.magic != SIMU_GAP_MAGIC)
Packit Service 392537
		goto bail_out;
Packit Service 392537
Packit Service 392537
	new_pos = cur_pos;
Packit Service 392537
	new_pos -= sizeof gap + gap.prev_size;
Packit Service 392537
Packit Service 392537
	ta->sent_leom = 0;
Packit Service 392537
Packit Service 392537
	/*
Packit Service 392537
	 * This is the new position. We need to update simu_prev_gap.
Packit Service 392537
	 */
Packit Service 392537
Packit Service 392537
	lseek (ta->tape_fd, new_pos, 0);
Packit Service 392537
Packit Service 392537
	rc = read (ta->tape_fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap || gap.magic != SIMU_GAP_MAGIC)
Packit Service 392537
		goto bail_out;
Packit Service 392537
Packit Service 392537
	switch (gap.rectype) {
Packit Service 392537
	case SIMU_GAP_RT_BOT:
Packit Service 392537
		/* can't actually back up to this, but update stuff */
Packit Service 392537
		ta->tape_state.file_num.value = 0;
Packit Service 392537
		ta->tape_state.blockno.value = 0;
Packit Service 392537
		/* cur_pos is now just right */
Packit Service 392537
		return 0;		/* can't back up */
Packit Service 392537
Packit Service 392537
	case SIMU_GAP_RT_EOT:
Packit Service 392537
		/* this just isn't suppose to happen */
Packit Service 392537
		goto bail_out;
Packit Service 392537
Packit Service 392537
	case SIMU_GAP_RT_DATA:
Packit Service 392537
		/* this is always OK */
Packit Service 392537
		if (ta->tape_state.blockno.value > 0)
Packit Service 392537
			ta->tape_state.blockno.value--;
Packit Service 392537
		lseek (ta->tape_fd, new_pos, 0);
Packit Service 392537
		return SIMU_GAP_RT_DATA;
Packit Service 392537
Packit Service 392537
	case SIMU_GAP_RT_FILE:
Packit Service 392537
		ta->tape_state.blockno.value = 0;
Packit Service 392537
		if (!over_file_mark) {
Packit Service 392537
			lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
			return 0;
Packit Service 392537
		}
Packit Service 392537
		if (ta->tape_state.file_num.value > 0)
Packit Service 392537
			ta->tape_state.file_num.value--;
Packit Service 392537
		lseek (ta->tape_fd, new_pos, 0);
Packit Service 392537
		return SIMU_GAP_RT_FILE;
Packit Service 392537
Packit Service 392537
	default:
Packit Service 392537
		/* this just isn't suppose to happen */
Packit Service 392537
		goto bail_out;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
  bail_out:
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
	return -1;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
int
Packit Service 392537
simu_forw_one (struct ndm_session *sess, int over_file_mark)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	struct simu_gap		gap;
Packit Service 392537
	off_t			cur_pos;
Packit Service 392537
	off_t			new_pos;
Packit Service 392537
	int			rc;
Packit Service 392537
Packit Service 392537
	cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
Packit Service 392537
Packit Service 392537
	rc = read (ta->tape_fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap || gap.magic != SIMU_GAP_MAGIC)
Packit Service 392537
		goto bail_out;
Packit Service 392537
Packit Service 392537
	ta->sent_leom = 0;
Packit Service 392537
Packit Service 392537
	new_pos = cur_pos;
Packit Service 392537
	new_pos += gap.size + sizeof gap;
Packit Service 392537
Packit Service 392537
	switch (gap.rectype) {
Packit Service 392537
	case SIMU_GAP_RT_BOT:
Packit Service 392537
		/* this just isn't suppose to happen */
Packit Service 392537
		goto bail_out;
Packit Service 392537
Packit Service 392537
	case SIMU_GAP_RT_EOT:
Packit Service 392537
		lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
		return 0;	/* can't go forward */
Packit Service 392537
Packit Service 392537
	case SIMU_GAP_RT_DATA:
Packit Service 392537
		/* this is always OK */
Packit Service 392537
		ta->tape_state.blockno.value++;
Packit Service 392537
		lseek (ta->tape_fd, new_pos, 0);
Packit Service 392537
		return SIMU_GAP_RT_DATA;
Packit Service 392537
Packit Service 392537
	case SIMU_GAP_RT_FILE:
Packit Service 392537
		if (!over_file_mark) {
Packit Service 392537
			lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
			return 0;
Packit Service 392537
		}
Packit Service 392537
		ta->tape_state.blockno.value = 0;
Packit Service 392537
		ta->tape_state.file_num.value++;
Packit Service 392537
		/* cur_pos is just right */
Packit Service 392537
		return SIMU_GAP_RT_FILE;
Packit Service 392537
Packit Service 392537
	default:
Packit Service 392537
		/* this just isn't suppose to happen */
Packit Service 392537
		goto bail_out;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
  bail_out:
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
	return -1;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
int
Packit Service 392537
simu_flush_weof (struct ndm_session *sess)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
Packit Service 392537
	if (ta->weof_on_close) {
Packit Service 392537
		/* best effort */
Packit Service 392537
		ndmos_tape_wfm (sess);
Packit Service 392537
	}
Packit Service 392537
	return 0;
Packit Service 392537
}
Packit Service 392537
		
Packit Service 392537
Packit Service 392537
ndmp9_error
Packit Service 392537
ndmos_tape_mtio (struct ndm_session *sess,
Packit Service 392537
  ndmp9_tape_mtio_op op, u_long count, u_long *resid)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	int			rc;
Packit Service 392537
Packit Service 392537
	*resid = count;
Packit Service 392537
Packit Service 392537
	if (ta->tape_fd < 0) {
Packit Service 392537
		return NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	/* audit for valid op and for tape mode */
Packit Service 392537
	switch (op) {
Packit Service 392537
	case NDMP9_MTIO_FSF:
Packit Service 392537
		while (*resid > 0) {
Packit Service 392537
			simu_flush_weof(sess);
Packit Service 392537
			rc = simu_forw_one (sess, 1);
Packit Service 392537
			if (rc < 0)
Packit Service 392537
				return NDMP9_IO_ERR;
Packit Service 392537
			if (rc == 0)
Packit Service 392537
				break;
Packit Service 392537
			if (rc == SIMU_GAP_RT_FILE)
Packit Service 392537
				*resid -= 1;
Packit Service 392537
		}
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	case NDMP9_MTIO_BSF:
Packit Service 392537
		while (*resid > 0) {
Packit Service 392537
			simu_flush_weof(sess);
Packit Service 392537
			rc = simu_back_one (sess, 1);
Packit Service 392537
			if (rc < 0)
Packit Service 392537
				return NDMP9_IO_ERR;
Packit Service 392537
			if (rc == 0)
Packit Service 392537
				break;
Packit Service 392537
			if (rc == SIMU_GAP_RT_FILE)
Packit Service 392537
				*resid -= 1;
Packit Service 392537
		}
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	case NDMP9_MTIO_FSR:
Packit Service 392537
		while (*resid > 0) {
Packit Service 392537
			simu_flush_weof(sess);
Packit Service 392537
			rc = simu_forw_one (sess, 0);
Packit Service 392537
			if (rc < 0)
Packit Service 392537
				return NDMP9_IO_ERR;
Packit Service 392537
			if (rc == 0)
Packit Service 392537
				break;
Packit Service 392537
			*resid -= 1;
Packit Service 392537
		}
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	case NDMP9_MTIO_BSR:
Packit Service 392537
		while (*resid > 0) {
Packit Service 392537
			simu_flush_weof(sess);
Packit Service 392537
			rc = simu_back_one (sess, 0);
Packit Service 392537
			if (rc < 0)
Packit Service 392537
				return NDMP9_IO_ERR;
Packit Service 392537
			if (rc == 0)
Packit Service 392537
				break;
Packit Service 392537
			*resid -= 1;
Packit Service 392537
		}
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	case NDMP9_MTIO_REW:
Packit Service 392537
		simu_flush_weof(sess);
Packit Service 392537
		*resid = 0;
Packit Service 392537
		ta->tape_state.file_num.value = 0;
Packit Service 392537
		ta->tape_state.blockno.value = 0;
Packit Service 392537
		lseek (ta->tape_fd, (off_t)(sizeof (struct simu_gap)), 0);
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	case NDMP9_MTIO_OFF:
Packit Service 392537
		simu_flush_weof(sess);
Packit Service 392537
		/* Hmmm. */
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	case NDMP9_MTIO_EOF:		/* should be "WFM" write-file-mark */
Packit Service 392537
		if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
Packit Service 392537
			return NDMP9_PERMISSION_ERR;
Packit Service 392537
		}
Packit Service 392537
		while (*resid > 0) {
Packit Service 392537
			ndmp9_error	err;
Packit Service 392537
Packit Service 392537
			err = ndmos_tape_wfm (sess);
Packit Service 392537
			if (err != NDMP9_NO_ERR)
Packit Service 392537
				return err;
Packit Service 392537
Packit Service 392537
			*resid -= 1;
Packit Service 392537
		}
Packit Service 392537
		break;
Packit Service 392537
Packit Service 392537
	default:
Packit Service 392537
		return NDMP9_ILLEGAL_ARGS_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	return NDMP9_NO_ERR;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
ndmp9_error
Packit Service 392537
ndmos_tape_write (struct ndm_session *sess,
Packit Service 392537
  char *buf, u_long count, u_long *done_count)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	int			rc;
Packit Service 392537
	struct simu_gap		gap;
Packit Service 392537
	off_t			cur_pos;
Packit Service 392537
	ndmp9_error		err;
Packit Service 392537
	u_long			prev_size;
Packit Service 392537
Packit Service 392537
	if (ta->tape_fd < 0) {
Packit Service 392537
		return NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
Packit Service 392537
		return NDMP9_PERMISSION_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (count == 0) {
Packit Service 392537
		/*
Packit Service 392537
		 * NDMPv4 clarification -- a tape read or write with
Packit Service 392537
		 * a count==0 is a no-op. This is undoubtedly influenced
Packit Service 392537
		 * by the SCSI Sequential Access specification which
Packit Service 392537
		 * says much the same thing.
Packit Service 392537
		 */
Packit Service 392537
		*done_count = 0;
Packit Service 392537
		return NDMP9_NO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
Packit Service 392537
Packit Service 392537
	if (o_tape_limit) {
Packit Service 392537
	    /* if cur_pos is past LEOM, but we haven't sent NDMP9_EOM_ERR yet,
Packit Service 392537
	     * then do so now */
Packit Service 392537
	    if (!ta->sent_leom && cur_pos > o_tape_limit - TAPE_SIM_LOGICAL_EOM) {
Packit Service 392537
		ta->sent_leom = 1;
Packit Service 392537
		return NDMP9_EOM_ERR;
Packit Service 392537
	    }
Packit Service 392537
Packit Service 392537
	    /* if this write will put us over PEOM, then send NDMP9_IO_ERR */
Packit Service 392537
	    if ((off_t)(cur_pos + sizeof gap + count) > o_tape_limit) {
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	    }
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	rc = read (ta->tape_fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap
Packit Service 392537
	 || gap.magic != SIMU_GAP_MAGIC) {
Packit Service 392537
		lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	prev_size = gap.prev_size;
Packit Service 392537
Packit Service 392537
	gap.magic = SIMU_GAP_MAGIC;
Packit Service 392537
	gap.rectype = SIMU_GAP_RT_DATA;
Packit Service 392537
	gap.prev_size = prev_size;
Packit Service 392537
	gap.size = count;
Packit Service 392537
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
Packit Service 392537
	if (write (ta->tape_fd, &gap, sizeof gap) == sizeof gap
Packit Service 392537
	 && (u_long)write (ta->tape_fd, buf, count) == count) {
Packit Service 392537
		cur_pos += count + sizeof gap;
Packit Service 392537
Packit Service 392537
		prev_size = count;
Packit Service 392537
Packit Service 392537
		ta->tape_state.blockno.value++;
Packit Service 392537
Packit Service 392537
		*done_count = count;
Packit Service 392537
Packit Service 392537
		err = NDMP9_NO_ERR;
Packit Service 392537
	} else {
Packit Service 392537
		err = NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
Packit Service 392537
	if (ftruncate (ta->tape_fd, cur_pos) < 0)
Packit Service 392537
	    return NDMP9_IO_ERR;
Packit Service 392537
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
Packit Service 392537
	gap.rectype = SIMU_GAP_RT_EOT;
Packit Service 392537
	gap.size = 0;
Packit Service 392537
	gap.prev_size = prev_size;
Packit Service 392537
Packit Service 392537
	if (write (ta->tape_fd, &gap, sizeof gap) < (int)sizeof gap)
Packit Service 392537
	    return NDMP9_IO_ERR;
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
Packit Service 392537
	if (o_tape_limit) {
Packit Service 392537
	    ta->tape_state.space_remain.value = o_tape_limit - cur_pos;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	ta->weof_on_close = 1;
Packit Service 392537
Packit Service 392537
	return err;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
ndmp9_error
Packit Service 392537
ndmos_tape_wfm (struct ndm_session *sess)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	int			rc;
Packit Service 392537
	struct simu_gap		gap;
Packit Service 392537
	off_t			cur_pos;
Packit Service 392537
	ndmp9_error		err;
Packit Service 392537
	u_long			prev_size;
Packit Service 392537
Packit Service 392537
	ta->weof_on_close = 0;
Packit Service 392537
Packit Service 392537
	if (ta->tape_fd < 0) {
Packit Service 392537
		return NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (!NDMTA_TAPE_IS_WRITABLE(ta)) {
Packit Service 392537
		return NDMP9_PERMISSION_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
Packit Service 392537
Packit Service 392537
	if (o_tape_limit) {
Packit Service 392537
	    /* note: filemarks *never* trigger NDMP9_EOM_ERR */
Packit Service 392537
Packit Service 392537
	    /* if this write will put us over PEOM, then send NDMP9_IO_ERR */
Packit Service 392537
	    if ((off_t)(cur_pos + sizeof gap) > o_tape_limit) {
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	    }
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	rc = read (ta->tape_fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap
Packit Service 392537
	 || gap.magic != SIMU_GAP_MAGIC) {
Packit Service 392537
		lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	prev_size = gap.prev_size;
Packit Service 392537
Packit Service 392537
	gap.magic = SIMU_GAP_MAGIC;
Packit Service 392537
	gap.rectype = SIMU_GAP_RT_FILE;
Packit Service 392537
	gap.prev_size = prev_size;
Packit Service 392537
	gap.size = 0;
Packit Service 392537
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
Packit Service 392537
	if (write (ta->tape_fd, &gap, sizeof gap) == sizeof gap) {
Packit Service 392537
Packit Service 392537
		cur_pos += sizeof gap;
Packit Service 392537
Packit Service 392537
		prev_size = 0;
Packit Service 392537
Packit Service 392537
		ta->tape_state.file_num.value++;
Packit Service 392537
		ta->tape_state.blockno.value = 0;
Packit Service 392537
Packit Service 392537
		err = NDMP9_NO_ERR;
Packit Service 392537
	} else {
Packit Service 392537
		err = NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (ftruncate (ta->tape_fd, cur_pos) < 0)
Packit Service 392537
	    return NDMP9_IO_ERR;
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
Packit Service 392537
	gap.rectype = SIMU_GAP_RT_EOT;
Packit Service 392537
	gap.size = 0;
Packit Service 392537
	gap.prev_size = prev_size;
Packit Service 392537
Packit Service 392537
	if (write (ta->tape_fd, &gap, sizeof gap) < (int)sizeof gap)
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
Packit Service 392537
	if (o_tape_limit) {
Packit Service 392537
	    ta->tape_state.space_remain.value = o_tape_limit - cur_pos;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	return err;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
ndmp9_error
Packit Service 392537
ndmos_tape_read (struct ndm_session *sess,
Packit Service 392537
  char *buf, u_long count, u_long *done_count)
Packit Service 392537
{
Packit Service 392537
	struct ndm_tape_agent *	ta = &sess->tape_acb;
Packit Service 392537
	int			rc;
Packit Service 392537
	struct simu_gap		gap;
Packit Service 392537
	off_t			cur_pos;
Packit Service 392537
Packit Service 392537
	if (ta->tape_fd < 0) {
Packit Service 392537
		return NDMP9_DEV_NOT_OPEN_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (count == 0) {
Packit Service 392537
		/*
Packit Service 392537
		 * NDMPv4 clarification -- a tape read or write with
Packit Service 392537
		 * a count==0 is a no-op. This is undoubtedly influenced
Packit Service 392537
		 * by the SCSI Sequential Access specification which
Packit Service 392537
		 * says much the same thing.
Packit Service 392537
		 */
Packit Service 392537
Packit Service 392537
		*done_count = 0;
Packit Service 392537
		return NDMP9_NO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	cur_pos = lseek (ta->tape_fd, (off_t)0, 1);
Packit Service 392537
Packit Service 392537
	rc = read (ta->tape_fd, &gap, sizeof gap);
Packit Service 392537
	if (rc != sizeof gap
Packit Service 392537
	 || gap.magic != SIMU_GAP_MAGIC) {
Packit Service 392537
		lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
		return NDMP9_IO_ERR;
Packit Service 392537
	}
Packit Service 392537
Packit Service 392537
	if (gap.rectype == SIMU_GAP_RT_DATA) {
Packit Service 392537
		unsigned	nb;
Packit Service 392537
Packit Service 392537
		nb = count;
Packit Service 392537
		if (nb > gap.size)
Packit Service 392537
			nb = gap.size;
Packit Service 392537
Packit Service 392537
		rc = read (ta->tape_fd, buf, nb);
Packit Service 392537
		if (rc != (int)nb) {
Packit Service 392537
			lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
			return NDMP9_IO_ERR;
Packit Service 392537
		}
Packit Service 392537
Packit Service 392537
		if (gap.size != nb) {
Packit Service 392537
			cur_pos += sizeof gap + gap.size;
Packit Service 392537
			lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
		}
Packit Service 392537
Packit Service 392537
		ta->tape_state.blockno.value++;
Packit Service 392537
Packit Service 392537
		*done_count = nb;
Packit Service 392537
	} else {
Packit Service 392537
		/* all other record types are interpretted as EOF */
Packit Service 392537
		lseek (ta->tape_fd, cur_pos, 0);
Packit Service 392537
		*done_count = 0;
Packit Service 392537
		return NDMP9_EOF_ERR;
Packit Service 392537
	}
Packit Service 392537
	return NDMP9_NO_ERR;
Packit Service 392537
}
Packit Service 392537
Packit Service 392537
#endif /* NDMOS_OPTION_TAPE_SIMULATOR */
Packit Service 392537
Packit Service 392537
#endif /* !NDMOS_OPTION_NO_TAPE_AGENT */