/*
* Copyright (c) 2015 by Delphix. All rights reserved.
*/
/*
* 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.
*/
#include <ctype.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <libzfs.h>
#include <pthread.h>
#include "tlm.h"
#include "tlm_proto.h"
#include <ndmpd_prop.h>
#include <thread.h>
#include <synch.h>
#include <sys/sysmacros.h>
/*
* Tar archiving ops vector
*/
"tar",
NULL,
};
extern libzfs_handle_t *zlibh;
/*
* get the next tape buffer from the drive's pool of buffers
*/
/*ARGSUSED*/
char *
{
char *rec;
/*
* make sure the allocation is in chunks of 512 bytes
*/
want += align_size;
want &= ~align_size;
if (*actual_size <= 0) {
/*
* no room, send this one
* and wait for a free one
*/
/*
* we are now ready to send a full buffer
* instead of trying to get a new buffer
*
* do not send if we failed to get a buffer
* on the previous call
*/
/*
* tell the writer that a buffer is available
*/
}
/*
* wait for the writer to free up a buffer
*/
}
/*
* the next buffer is still full
* of data from previous activity
*
* nothing has changed.
*/
return (0);
}
buffer->tb_buffer_spot = 0;
}
if (zero) {
}
return (rec);
}
/*
* get a read record from the tape buffer,
* and read a tape block if necessary
*/
/*ARGSUSED*/
char *
{
int buf;
int current_size;
char *rec;
/*
* make sure the allocation is in chunks of 512 bytes
*/
want += align_size;
want &= ~align_size;
/*
* no more data, release this
* one and go get another
*/
/*
* tell the reader that a buffer is available
*/
}
/*
* next buffer is not full yet.
* wait for the reader.
*/
/*
* we do not have anything from the tape yet
*/
return (0);
}
}
/* Make sure we got something */
if (current_size <= 0)
return (NULL);
/*
* the error flag is only sent back one time,
* since the flag refers to a previous read
* attempt, not the data in this buffer.
*/
return (rec);
}
/*
* unread a previously read buffer back to the tape buffer
*/
void
{
int buf;
int current_size;
/*
* make sure the allocation is in chunks of 512 bytes
*/
size += align_size;
size &= ~align_size;
}
/*
* unwrite a previously written buffer
*/
void
{
int buf;
int current_size;
/*
* make sure the allocation is in chunks of 512 bytes
*/
size += align_size;
size &= ~align_size;
}
/*
* build a checksum for a TAR header record
*/
void
{
int i;
int sum = 0;
char *c = (char *)r;
for (i = 0; i < RECORDSIZE; i++) {
sum += c[i] & 0xFF;
}
}
/*
* verify the tar header checksum
*/
int
{
int i; /* loop counter */
/*
* compute the checksum
*/
for (i = 0; i < RECORDSIZE; i++) {
sum += p[i] & 0xFF;
}
if (sum == 0) {
"should be %d, is 0", chksum);
/* a zero record ==> end of tar file */
return (0);
}
/*
* subtract out the label's checksum values
* this lets us undo the old checksum "in-
* place", no need to swap blanks in and out
*/
for (i = 0; i < 8; i++) {
}
/*
* replace the old checksum field with blanks
*/
}
/*
* get internal scsi_sasd entry for this tape drive
*/
int
{
int entry;
int i, n;
entry = -1;
if (!dp) {
} else {
/* search through the SASD table */
n = sasd_dev_count();
for (i = 0; i < n; i++) {
sl = sasd_dev_slink(i);
if (!sl)
continue;
/* all 3 variables match */
entry = i;
break;
}
}
}
return (entry);
}
/*
* get the OS device name for this tape
*/
char *
{
int entry;
if (entry >= 0) {
}
return ("");
}
/*
* create the IPC area between the reader and writer
*/
{
return (NULL);
return (NULL);
}
return (cmd);
}
/*
* release(destroy) the IPC between the reader and writer
*/
void
{
}
}
/*
* NDMP support begins here.
*/
/*
* Initialize the file history callback functions
*/
{
p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t));
if (p == NULL)
return (NULL);
return (p);
}
/*
* Cleanup the callbacks
*/
void
{
if (p != NULL)
(void) free((char *)p);
}
/*
* Call back for file history directory info
*/
int
{
int rv;
rv = 0;
== NULL) {
} else
return (rv);
}
/*
* Call back for file history node info
*/
int
{
int rv;
rv = 0;
== NULL) {
} else
return (rv);
}
/*
* Call back for file history path info
*/
int
{
int rv;
rv = 0;
if (!job_stats) {
} else if (!pathname) {
} else if (!stp) {
== 0) {
} else if (!cbp->fh_logpname) {
} else
return (rv);
}
/*
* Log call back to report the entry recovery
*/
int
{
return (0);
}
return (0);
}
}
/*
* NDMP support ends here.
*/
/*
* Function: tlm_cat_path
* Concatenates two path names
* or directory name and file name
* into a buffer passed by the caller. A slash
* is inserted if required. Buffer is assumed
* to hold PATH_MAX characters.
*
* Parameters:
* char *dir - directory name
* char *name - file name
*
* Returns:
* FALSE - Error. buf is not modified.
*/
{
char *fmt;
return (FALSE);
}
*name == '/') {
fmt = "%s%s";
} else {
fmt = "%s/%s";
}
/* check for ".../" and "/...." */
/* LINTED variable format */
return (TRUE);
}
/*
* Get the checkpoint (snapshot) creation time.
* This is necessary to check for checkpoints not being stale.
*/
int
{
char *cp_nm;
return (-1);
path) == -1)
return (-1);
if (auto_checkpoint) {
}
}
/*
* Release an array of pointers and the pointers themselves.
*/
void
{
char **save;
return;
while (*lpp)
}
/*
* Print the list of array of strings in the backup log
*/
void
{
int i;
if (!lpp)
return;
}
/*
* Insert the backup snapshot name into the path.
*
* Input:
* name: Original path name.
*
* Output:
* name: Original name modified to include a snapshot.
*
* Returns:
* Original name modified to include a snapshot.
*/
char *
{
char *rest;
goto notzfs;
(void) mutex_lock(&zlib_mtx);
(void) mutex_unlock(&zlib_mtx);
goto notzfs;
}
(void) mutex_unlock(&zlib_mtx);
goto notzfs;
}
(void) mutex_unlock(&zlib_mtx);
return (sname);
return (sname);
}
/*
* Remove the checkpoint from a path name.
*
* Input:
* name: Full pathname with checkpoint embeded.
*
* Output:
* unchkp_name: real pathname with no checkpoint.
*
* Returns:
* Pointer to the un-checkpointed path.
*/
char *
{
char *cp;
int i;
int plen;
unchkp_name[0] = name[0];
switch (name[i]) {
case '.':
plen) == 0) {
unchkp_name[i] = '\0';
i += plen;
if (name[i] == '\0') {
/*
* name == "/v1.chkpnt"
*/
return (unchkp_name);
}
TLM_VOLNAME_MAX_LENGTH + 1);
}
return (unchkp_name);
} else {
unchkp_name[i] = name[i];
}
break;
case '/':
return (name);
case 0:
return (name);
default:
unchkp_name[i] = name[i];
break;
}
}
return (name);
}
/*
* see if we should exclude this file.
*/
{
int i;
return (FALSE);
return (FALSE);
}
for (i = 0; excl_files[i] != 0; i++) {
return (TRUE);
}
}
return (FALSE);
}
/*
* Check if the path is too long
*/
{
tot = 0;
if (dir)
if (checkpointed)
if (nm) {
}
}
/*
* Get the data offset of inside the buffer
*/
{
if (!lcmds)
return (0LL);
}
/*
* Enable the barcode capability on the library
*/
void
tlm_enable_barcode(int l)
{
if ((lp = tlm_library(l))) {
"Barcode capability on library %d enabled.", l);
}
}
/*
* SASD SCSI support
*/
static int sasd_drive_count = 0;
/*
* Count of SCSI devices
*/
int
sasd_dev_count(void)
{
return (sasd_drive_count);
}
/*
* Return the SCSI device name
*/
char *
{
int i;
for (i = 0; i < sasd_drive_count; i++) {
}
return (NULL);
}
/*
* Return the SCSI drive structure
*/
{
int i;
for (i = 0; i < sasd_drive_count; i++) {
return (&scsi_sasd_drives[i]->ss_sd);
}
return (NULL);
}
/*
* Return the SCSI link pointer for the given index
*/
{
else
return (rv);
}
/*
* Return the SCSI drive for the given index
*/
{
else
return (rv);
}
/*
* Attach the SCSI device by updating the structures
*/
void
int type)
{
return;
switch (type) {
case DTYPE_CHANGER:
name);
break;
case DTYPE_SEQUENTIAL:
break;
}
/* Insert slink */
}
/*
* Go through the attached devices and detect the tape
* and robot by checking the /dev entries
*/
int
probe_scsi(void)
{
char *p;
int lun = 0;
int sid = 0;
char *drive_type;
/* Initialize the scsi adapter link */
/* Scan for the changer */
"Changer directory read error %s", SCSI_CHANGER_DIR);
} else {
continue;
}
else
}
}
/* Scan for tape drives */
"Tape directory read error %s", SCSI_TAPE_DIR);
} else {
"Valid values are 'sysv' and 'bsd'.");
return (-1);
}
continue;
/* Skip special modes */
continue;
/* Pick the non-rewind device */
continue;
continue;
continue;
}
/*
* SCSI ID should match with the ID of the device
* (will be checked by SCSI get elements page later)
*/
}
}
return (0);
}
/*
* Get the SCSI device type (tape, robot)
*/
/*ARGSUSED*/
int
{
int rv;
rv = -1;
return (rv);
}
/*
* Check if the SCSI device exists
*/
/*ARGSUSED*/
int
{
return (1);
return (0);
}
/*
* Count of SCSI adapters
*/
int
scsi_get_adapter_count(void)
{
/* Currently support one adapter only */
return (1);
}
/*
* Return the SCSI adapter structure
*/
/*ARGSUSED*/
{
return (&my_sa);
}
/*
* IOCTL wrapper with retries
*/
int
{
int retries = 0;
return (EINVAL);
do {
break;
"Failed to send command to device: %m.");
return (errno);
}
(void) sleep(1);
} while (retries++ < MAXIORETRY);
return (0);
}
/*
* Checkpoint or snapshot calls
*/
/*
* Get the snapshot creation time
*/
int
{
char *p;
return (-1);
/* Should also return -1 if checkpoint not enabled */
/* Remove the leading slash */
p = volname;
while (*p == '/')
p++;
(void) mutex_lock(&zlib_mtx);
chk_name);
(void) mutex_unlock(&zlib_mtx);
return (-1);
}
(void) mutex_unlock(&zlib_mtx);
return (0);
}
/*
* Get the ZFS volume name out of the given path
*/
int
{
int rv;
*volname = '\0';
return (-1);
}
return (-1);
}
break;
}
if (rv == 0 &&
else
rv = -1;
return (rv);
}
/*
* Check if the volume type is snapshot volume
*/
{
return (FALSE);
return (FALSE);
(void) mutex_lock(&zlib_mtx);
(void) mutex_unlock(&zlib_mtx);
return (FALSE);
}
(void) mutex_unlock(&zlib_mtx);
return (FALSE);
}
(void) mutex_unlock(&zlib_mtx);
return (TRUE);
}
/*
* Check if the volume is capable of checkpoints
*/
{
return (FALSE);
(void) mutex_lock(&zlib_mtx);
(void) mutex_unlock(&zlib_mtx);
return (FALSE);
}
(void) mutex_unlock(&zlib_mtx);
return (FALSE);
}
(void) mutex_unlock(&zlib_mtx);
return (TRUE);
}
/*
* Check if the volume is read-only
*/
{
return (fs_is_chkpntvol(path));
}
/*
*/
unsigned
min(unsigned a, unsigned b)
{
return (a < b ? a : b);
}
unsigned
max(unsigned a, unsigned b)
{
return (a > b ? a : b);
}
{
return (a < b ? a : b);
}