ndmpd_tape.c revision 2654012f83cec5dc15b61dfe3e4a4915f186e7a6
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* BSD 3 Clause License
*
* Copyright (c) 2007, The Storage Networking Industry Association.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* - Neither the name of The Storage Networking Industry Association (SNIA)
* nor the names of its contributors may be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
*/
/* Copyright (c) 2007, The Storage Networking Industry Association. */
/* Copyright (c) 1996, 1997 PDC, Network Appliance. All Rights Reserved */
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ndmpd_common.h"
#include "ndmpd.h"
int ndmpmode);
/*
* Configurable delay & time when the tape is
* busy during opening the tape.
*/
int ndmp_tape_open_retries = 5;
int ndmp_tape_open_delay = 1000;
/*
* ************************************************************************
* NDMP V2 HANDLERS
* ************************************************************************
*/
/*
* ndmpd_tape_open_v2
*
* This handler opens the specified tape device.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
char adptnm[SCSI_MAX_NAME];
int mode;
int err;
int devid;
err = NDMP_NO_ERR;
"Connection already has a tape or scsi device open");
}
}
/* try to get the scsi id etc.... */
if (sa) {
}
else
} else {
}
if (err != NDMP_NO_ERR) {
return;
}
case 0:
err = NDMP_NO_ERR;
break;
case EBUSY:
break;
case ENOMEM:
break;
default:
err = NDMP_IO_ERR;
}
if (err != NDMP_NO_ERR) {
return;
}
/*
* According to Connectathon 2001, the 0x7fffffff is a secret
* code between "Workstartion Solutions" and * net_app.
* If mode is set to this value, tape_open() won't fail if
* the tape device is not ready.
*/
!is_tape_unit_ready(adptnm, 0)) {
return;
}
switch (errno) {
case EACCES:
break;
case ENXIO:
case ENOENT:
break;
case EBUSY:
break;
default:
err = NDMP_IO_ERR;
}
return;
}
}
/*
* ndmpd_tape_close_v2
*
* This handler closes the currently open tape device.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
/*ARGSUSED*/
void
{
"sending tape_close reply");
return;
}
}
/*
* ndmpd_tape_get_state_v2
*
* This handler handles the tape_get_state request.
* Status information for the currently open tape device is returned.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
/*ARGSUSED*/
void
{
struct mtdrivetype_request dtpr;
struct mtdrivetype dtp;
"sending tape_get_state reply");
return;
}
"sending tape_get_state reply");
return;
}
"Failed to get drive type information from tape: %m.");
"sending tape_get_state reply");
return;
}
reply.soft_errors = 0;
else
reply.soft_errors = 0;
"flags: 0x%x, file_num: %d, block_size: %d, blockno: %d",
"sending tape_get_state reply");
}
/*
* ndmpd_tape_mtio_v2
*
* This handler handles tape_mtio requests.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
int retry = 0;
int rc;
reply.resid_count = 0;
"sending tape_mtio reply");
return;
}
case NDMP_MTIO_FSF:
break;
case NDMP_MTIO_BSF:
break;
case NDMP_MTIO_FSR:
break;
case NDMP_MTIO_BSR:
break;
case NDMP_MTIO_REW:
break;
case NDMP_MTIO_EOF:
break;
case NDMP_MTIO_OFF:
break;
case NDMP_MTIO_TUR: /* test unit ready */
/* tape not ready ? */
break;
default:
}
do {
"ioctl MTIO rc:%d, cmd:%d, retry:%d, error: %d",
retry++ < 5);
/*
* Ignore I/O errors since these usually are the result of
* attempting to position past the beginning or end of the tape.
* The residual count will be returned and can be used to
* determine that the call was not completely successful.
*/
if (rc < 0) {
"Failed to send command to tape: %m.");
/* MTWEOF doesnt have residual count */
else
"sending tape_mtio reply");
return;
}
&mtstatus) < 0) {
"Failed to send command to tape: %m.");
"ioctl(MTIOCGET) error: %m.");
"sending tape_mtio reply");
return;
}
}
}
}
/*
* ndmpd_tape_write_v2
*
* This handler handles tape_write requests.
* This interface is a non-buffered interface. Each write request
* maps directly to a write to the tape device. It is the responsibility
* of the NDMP client to pad the data to the desired record size.
* It is the responsibility of the NDMP client to ensure that the
* length is a multiple of the tape block size if the tape device
* is in fixed block mode.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
ssize_t n;
"sending tape_write reply");
return;
}
"sending tape_write reply");
return;
}
"sending tape_write reply");
return;
}
/*
* Refer to the comment at the top of this file for
* Mammoth2 tape drives.
*/
"sending tape_write reply");
return;
}
if (n >= 0) {
}
if (n == 0) {
} else if (n < 0) {
} else {
/*
* a logical end of tape will return number of bytes written
* less than rquested, and one more request to write will
* give 0, and then no-space
*/
} else {
}
}
"sending tape_write reply");
}
/*
* ndmpd_tape_read_v2
*
* This handler handles tape_read requests.
* This interface is a non-buffered interface. Each read request
* maps directly to a read to the tape device. It is the responsibility
* of the NDMP client to issue read requests with a length that is at
* least as large as the record size used write the tape. The tape driver
* always reads a full record. Data is discarded if the read request is
* smaller than the record size.
* It is the responsibility of the NDMP client to ensure that the
* length is a multiple of the tape block size if the tape device
* is in fixed block mode.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
char *buf;
"sending tape_read reply");
return;
}
"sending tape_read reply");
return;
}
"sending tape_read reply");
return;
}
}
/*
* ndmpd_tape_execute_cdb_v2
*
* This handler handles tape_execute_cdb requests.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
"sending tape_execute_cdb reply");
} else {
}
}
/*
* ************************************************************************
* NDMP V3 HANDLERS
* ************************************************************************
*/
/*
* ndmpd_tape_open_v3
*
* This handler opens the specified tape device.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
}
/*
* ndmpd_tape_get_state_v3
*
* This handler handles the ndmp_tape_get_state_request.
* Status information for the currently open tape device is returned.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
/*ARGSUSED*/
void
{
struct mtdrivetype_request dtpr;
struct mtdrivetype dtp;
"sending tape_get_state reply");
return;
}
"sending tape_get_state reply");
return;
}
"Failed to get drive type information from tape: %m.");
"sending tape_get_state reply");
return;
}
reply.soft_errors = 0;
else
reply.soft_errors = 0;
"sending tape_get_state reply");
}
/*
* ndmpd_tape_write_v3
*
* This handler handles tape_write requests.
* This interface is a non-buffered interface. Each write request
* maps directly to a write to the tape device. It is the responsibility
* of the NDMP client to pad the data to the desired record size.
* It is the responsibility of the NDMP client to ensure that the
* length is a multiple of the tape block size if the tape device
* is in fixed block mode.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
ssize_t n;
"sending tape_write reply");
return;
}
"sending tape_write reply");
return;
}
"sending tape_write reply");
return;
}
/*
* V4 suggests that this should not be accepted
* when mover is in listen or active state
*/
"sending tape_write reply");
return;
}
/*
* Refer to the comment at the top of this file for
* Mammoth2 tape drives.
*/
"sending tape_write reply");
return;
}
if (n >= 0) {
}
if (n == 0) {
} else if (n < 0) {
} else {
}
"sending tape_write reply");
}
/*
* ndmpd_tape_read_v3
*
* This handler handles tape_read requests.
* This interface is a non-buffered interface. Each read request
* maps directly to a read to the tape device. It is the responsibility
* of the NDMP client to issue read requests with a length that is at
* least as large as the record size used write the tape. The tape driver
* always reads a full record. Data is discarded if the read request is
* smaller than the record size.
* It is the responsibility of the NDMP client to ensure that the
* length is a multiple of the tape block size if the tape device
* is in fixed block mode.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
void
{
char *buf;
int n, len;
"sending tape_read reply");
return;
}
"sending tape_read reply");
return;
}
/*
* V4 suggests that this should not be accepted
* when mover is in listen or active state
*/
"sending tape_read reply");
return;
}
"sending tape_read reply");
return;
}
if (n < 0) {
/*
* This fix is for Symantec during importing
* of spanned data between the tapes.
*/
} else {
}
} else if (n == 0) {
} else {
}
if (n > 0)
} else {
/*
* Symantec fix for import phase
*
* As import process from symantec skips filemarks
* they can come across to NDMP_EOM_MAGIC and treat
* it as data. This fix prevents the magic to be
* sent to the client and the read will return zero bytes
* and set the NDMP_EOM_ERR error. The tape should
* be positioned at the EOT side of the file mark.
*/
} else {
}
}
}
/*
* ************************************************************************
* NDMP V4 HANDLERS
* ************************************************************************
*/
/*
* ndmpd_tape_get_state_v4
*
* This handler handles the ndmp_tape_get_state_request.
* Status information for the currently open tape device is returned.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
/*ARGSUSED*/
void
{
struct mtdrivetype_request dtpr;
struct mtdrivetype dtp;
"sending tape_get_state reply");
return;
}
/*
* Need code to detect NDMP_TAPE_STATE_NOREWIND
*/
"Failed to get status information from tape: %m.");
"sending tape_get_state reply");
return;
}
"Failed to get drive type information from tape: %m.");
"sending tape_get_state reply");
return;
}
reply.soft_errors = 0;
else
reply.soft_errors = 0;
"sending tape_get_state reply");
}
/*
* ndmpd_tape_close_v4
*
* This handler (v4) closes the currently open tape device.
*
* Parameters:
* connection (input) - connection handle.
* body (input) - request message body.
*
* Returns:
* void
*/
/*ARGSUSED*/
void
{
"sending tape_close reply");
return;
}
/*
* V4 suggests that this should not be accepted
* when mover is in listen or active state
*/
"sending tape_close reply");
return;
}
}
/*
* ************************************************************************
* LOCALS
* ************************************************************************
*/
/*
* tape_open_send_reply
*
* Send a reply to the tape open message
*
* Parameters:
* connection (input) - connection handle.
* err (input) - NDMP error
*
* Returns:
* void
*/
static void
{
}
/*
* unbuffered_read
*
* Perform tape read without read-ahead
*
* Parameters:
* session (input) - session handle
* bp (output) - read buffer
* wanted (input) - number of bytes wanted
* reply (output) - tape read reply message
*
* Returns:
* void
*/
static void
{
int n, len;
if (n < 0) {
/*
* This fix is for Symantec during importing
* of spanned data between the tapes.
*/
} else {
}
} else if (n == 0) {
} else {
}
}
/*
* validmode
*
* Check the tape read mode is valid
*/
static boolean_t
{
switch (mode) {
case NDMP_TAPE_READ_MODE:
case NDMP_TAPE_WRITE_MODE:
case NDMP_TAPE_RAW1_MODE:
case NDMP_TAPE_RAW2_MODE:
break;
default:
}
return (rv);
}
/*
* common_tape_open
*
* Generic function for opening the tape for all versions
*
* Parameters:
* connection (input) - connection handle.
* devname (input) - tape device name to open.
* ndmpmode (input) - mode of opening (read, write, raw)
*
* Returns:
* void
*/
static void
{
char adptnm[SCSI_MAX_NAME];
int err;
int mode;
int devid;
err = NDMP_NO_ERR;
"Connection already has a tape or scsi device open");
}
if (sa) {
"Failed to open device %s: %m.", devname);
} else {
}
} else {
}
if (err != NDMP_NO_ERR) {
return;
}
/*
* If tape is not opened in raw mode and tape is not loaded
* return error.
*/
if (ndmpmode != NDMP_TAPE_RAW1_MODE &&
ndmpmode != NDMP_TAPE_RAW2_MODE &&
!is_tape_unit_ready(adptnm, 0)) {
return;
}
/*
* V4 suggests that if the tape is open in raw mode
* and could not be opened with write access, it should
* be opened read only instead.
*/
}
devname);
switch (errno) {
case EACCES:
break;
case ENOENT:
break;
case EBUSY:
break;
case EPERM:
break;
default:
err = NDMP_IO_ERR;
}
return;
}
switch (ndmp_open_list_add(connection,
case 0:
err = NDMP_NO_ERR;
break;
case EBUSY:
break;
case ENOMEM:
break;
default:
err = NDMP_IO_ERR;
}
if (err != NDMP_NO_ERR) {
return;
}
}
/*
* common_tape_close
*
* Generic function for closing the tape
*
* Parameters:
* connection (input) - connection handle.
*
* Returns:
* void
*/
static void
{
"sending tape_close reply");
}
/*
* tape_open
*
* Will try to open the tape with the given flags and
* path using the given retries and delay intervals
*/
int
{
int fd;
int i = 0;
i++ < ndmp_tape_open_retries) {
break;
(void) usleep(ndmp_tape_open_delay);
}
return (fd);
}