xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_lib.c (revision 9adfa60d)
12654012fSReza Sabdar /*
28c4f9701SJanice Chang  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3*9adfa60dSMatthew Ahrens  * Copyright (c) 2015 by Delphix. All rights reserved.
42654012fSReza Sabdar  */
52654012fSReza Sabdar 
62654012fSReza Sabdar /*
72654012fSReza Sabdar  * BSD 3 Clause License
82654012fSReza Sabdar  *
92654012fSReza Sabdar  * Copyright (c) 2007, The Storage Networking Industry Association.
102654012fSReza Sabdar  *
112654012fSReza Sabdar  * Redistribution and use in source and binary forms, with or without
122654012fSReza Sabdar  * modification, are permitted provided that the following conditions
132654012fSReza Sabdar  * are met:
142654012fSReza Sabdar  * 	- Redistributions of source code must retain the above copyright
152654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer.
162654012fSReza Sabdar  *
172654012fSReza Sabdar  * 	- Redistributions in binary form must reproduce the above copyright
182654012fSReza Sabdar  *	  notice, this list of conditions and the following disclaimer in
192654012fSReza Sabdar  *	  the documentation and/or other materials provided with the
202654012fSReza Sabdar  *	  distribution.
212654012fSReza Sabdar  *
222654012fSReza Sabdar  *	- Neither the name of The Storage Networking Industry Association (SNIA)
232654012fSReza Sabdar  *	  nor the names of its contributors may be used to endorse or promote
242654012fSReza Sabdar  *	  products derived from this software without specific prior written
252654012fSReza Sabdar  *	  permission.
262654012fSReza Sabdar  *
272654012fSReza Sabdar  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
282654012fSReza Sabdar  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
292654012fSReza Sabdar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
302654012fSReza Sabdar  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
312654012fSReza Sabdar  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
322654012fSReza Sabdar  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
332654012fSReza Sabdar  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
342654012fSReza Sabdar  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
352654012fSReza Sabdar  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
362654012fSReza Sabdar  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
372654012fSReza Sabdar  * POSSIBILITY OF SUCH DAMAGE.
382654012fSReza Sabdar  */
392654012fSReza Sabdar #include <sys/errno.h>
402654012fSReza Sabdar #include <ctype.h>
412654012fSReza Sabdar #include <stdlib.h>
422654012fSReza Sabdar #include <time.h>
432654012fSReza Sabdar #include <sys/types.h>
442654012fSReza Sabdar #include <unistd.h>
452654012fSReza Sabdar #include <libzfs.h>
462654012fSReza Sabdar #include <pthread.h>
472654012fSReza Sabdar #include "tlm.h"
482654012fSReza Sabdar #include "tlm_proto.h"
491e05b03fSJanice Chang #include <ndmpd_prop.h>
502654012fSReza Sabdar #include <sys/mtio.h>
512654012fSReza Sabdar #include <sys/mnttab.h>
522654012fSReza Sabdar #include <sys/mntent.h>
532654012fSReza Sabdar #include <sys/statvfs.h>
542654012fSReza Sabdar #include <sys/scsi/impl/uscsi.h>
552654012fSReza Sabdar #include <sys/scsi/scsi.h>
562654012fSReza Sabdar #include <sys/mtio.h>
572654012fSReza Sabdar #include <thread.h>
582654012fSReza Sabdar #include <synch.h>
592654012fSReza Sabdar #include <sys/mutex.h>
602654012fSReza Sabdar #include <sys/sysmacros.h>
612654012fSReza Sabdar #include <sys/mkdev.h>
622654012fSReza Sabdar 
632654012fSReza Sabdar /*
642654012fSReza Sabdar  * Tar archiving ops vector
652654012fSReza Sabdar  */
662654012fSReza Sabdar tm_ops_t tm_tar_ops = {
672654012fSReza Sabdar 	"tar",
682654012fSReza Sabdar 	tar_putfile,
692654012fSReza Sabdar 	tar_putdir,
702654012fSReza Sabdar 	NULL,
712654012fSReza Sabdar 	tar_getfile,
722654012fSReza Sabdar 	tar_getdir,
732654012fSReza Sabdar 	NULL
742654012fSReza Sabdar };
752654012fSReza Sabdar 
762654012fSReza Sabdar extern	libzfs_handle_t *zlibh;
772654012fSReza Sabdar extern	mutex_t zlib_mtx;
782654012fSReza Sabdar 
792654012fSReza Sabdar /*
802654012fSReza Sabdar  * get the next tape buffer from the drive's pool of buffers
812654012fSReza Sabdar  */
822654012fSReza Sabdar /*ARGSUSED*/
832654012fSReza Sabdar char *
tlm_get_write_buffer(long want,long * actual_size,tlm_buffers_t * buffers,int zero)842654012fSReza Sabdar tlm_get_write_buffer(long want, long *actual_size,
852654012fSReza Sabdar     tlm_buffers_t *buffers, int zero)
862654012fSReza Sabdar {
872654012fSReza Sabdar 	int	buf = buffers->tbs_buffer_in;
882654012fSReza Sabdar 	tlm_buffer_t *buffer = &buffers->tbs_buffer[buf];
892654012fSReza Sabdar 	int	align_size = RECORDSIZE - 1;
902654012fSReza Sabdar 	char	*rec;
912654012fSReza Sabdar 
922654012fSReza Sabdar 	/*
932654012fSReza Sabdar 	 * make sure the allocation is in chunks of 512 bytes
942654012fSReza Sabdar 	 */
952654012fSReza Sabdar 	want += align_size;
962654012fSReza Sabdar 	want &= ~align_size;
972654012fSReza Sabdar 
982654012fSReza Sabdar 	*actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
992654012fSReza Sabdar 	if (*actual_size <= 0) {
1002654012fSReza Sabdar 		/*
1012654012fSReza Sabdar 		 * no room, send this one
1022654012fSReza Sabdar 		 * and wait for a free one
1032654012fSReza Sabdar 		 */
1042654012fSReza Sabdar 		if (!buffer->tb_full) {
1052654012fSReza Sabdar 			/*
1062654012fSReza Sabdar 			 * we are now ready to send a full buffer
1072654012fSReza Sabdar 			 * instead of trying to get a new buffer
1082654012fSReza Sabdar 			 *
1092654012fSReza Sabdar 			 * do not send if we failed to get a buffer
1102654012fSReza Sabdar 			 * on the previous call
1112654012fSReza Sabdar 			 */
1122654012fSReza Sabdar 			buffer->tb_full = TRUE;
1132654012fSReza Sabdar 
1142654012fSReza Sabdar 			/*
1152654012fSReza Sabdar 			 * tell the writer that a buffer is available
1162654012fSReza Sabdar 			 */
1172654012fSReza Sabdar 			tlm_buffer_release_in_buf(buffers);
1182654012fSReza Sabdar 
1192654012fSReza Sabdar 			buffer = tlm_buffer_advance_in_idx(buffers);
1202654012fSReza Sabdar 		}
1212654012fSReza Sabdar 
1222654012fSReza Sabdar 		buffer = tlm_buffer_in_buf(buffers, NULL);
1232654012fSReza Sabdar 
1242654012fSReza Sabdar 		if (buffer->tb_full) {
1252654012fSReza Sabdar 			/*
1262654012fSReza Sabdar 			 * wait for the writer to free up a buffer
1272654012fSReza Sabdar 			 */
1282654012fSReza Sabdar 			tlm_buffer_out_buf_timed_wait(buffers, 500);
1292654012fSReza Sabdar 		}
1302654012fSReza Sabdar 
1312654012fSReza Sabdar 		buffer = tlm_buffer_in_buf(buffers, NULL);
1322654012fSReza Sabdar 		if (buffer->tb_full) {
1332654012fSReza Sabdar 			/*
1342654012fSReza Sabdar 			 * the next buffer is still full
1352654012fSReza Sabdar 			 * of data from previous activity
1362654012fSReza Sabdar 			 *
1372654012fSReza Sabdar 			 * nothing has changed.
1382654012fSReza Sabdar 			 */
1392654012fSReza Sabdar 			return (0);
1402654012fSReza Sabdar 		}
1412654012fSReza Sabdar 
1422654012fSReza Sabdar 		buffer->tb_buffer_spot = 0;
1432654012fSReza Sabdar 		*actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
1442654012fSReza Sabdar 	}
1452654012fSReza Sabdar 
1462654012fSReza Sabdar 	*actual_size = min(want, *actual_size);
1472654012fSReza Sabdar 	rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot];
1482654012fSReza Sabdar 	buffer->tb_buffer_spot += *actual_size;
1492654012fSReza Sabdar 	buffers->tbs_offset += *actual_size;
1502654012fSReza Sabdar 	if (zero) {
1512654012fSReza Sabdar 		(void) memset(rec, 0, *actual_size);
1522654012fSReza Sabdar 	}
1532654012fSReza Sabdar 	return (rec);
1542654012fSReza Sabdar }
1552654012fSReza Sabdar 
1562654012fSReza Sabdar /*
1572654012fSReza Sabdar  * get a read record from the tape buffer,
1582654012fSReza Sabdar  * and read a tape block if necessary
1592654012fSReza Sabdar  */
1602654012fSReza Sabdar /*ARGSUSED*/
1612654012fSReza Sabdar char *
tlm_get_read_buffer(int want,int * error,tlm_buffers_t * buffers,int * actual_size)1622654012fSReza Sabdar tlm_get_read_buffer(int want, int *error,
1632654012fSReza Sabdar     tlm_buffers_t *buffers, int *actual_size)
1642654012fSReza Sabdar {
1652654012fSReza Sabdar 	tlm_buffer_t *buffer;
1662654012fSReza Sabdar 	int	align_size = RECORDSIZE - 1;
1672654012fSReza Sabdar 	int	buf;
1682654012fSReza Sabdar 	int	current_size;
1692654012fSReza Sabdar 	char	*rec;
1702654012fSReza Sabdar 
1712654012fSReza Sabdar 	buf = buffers->tbs_buffer_out;
1722654012fSReza Sabdar 	buffer = &buffers->tbs_buffer[buf];
1732654012fSReza Sabdar 
1742654012fSReza Sabdar 	/*
1752654012fSReza Sabdar 	 * make sure the allocation is in chunks of 512 bytes
1762654012fSReza Sabdar 	 */
1772654012fSReza Sabdar 	want += align_size;
1782654012fSReza Sabdar 	want &= ~align_size;
1792654012fSReza Sabdar 
1802654012fSReza Sabdar 	current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
1812654012fSReza Sabdar 	if (buffer->tb_full && current_size <= 0) {
1822654012fSReza Sabdar 		/*
1832654012fSReza Sabdar 		 * no more data, release this
1842654012fSReza Sabdar 		 * one and go get another
1852654012fSReza Sabdar 		 */
1862654012fSReza Sabdar 
1872654012fSReza Sabdar 		/*
1882654012fSReza Sabdar 		 * tell the reader that a buffer is available
1892654012fSReza Sabdar 		 */
1902654012fSReza Sabdar 		buffer->tb_full = FALSE;
1912654012fSReza Sabdar 		tlm_buffer_release_out_buf(buffers);
1922654012fSReza Sabdar 
1932654012fSReza Sabdar 		buffer = tlm_buffer_advance_out_idx(buffers);
1942654012fSReza Sabdar 		current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
1952654012fSReza Sabdar 	}
1962654012fSReza Sabdar 
1972654012fSReza Sabdar 	if (!buffer->tb_full) {
1982654012fSReza Sabdar 		/*
1992654012fSReza Sabdar 		 * next buffer is not full yet.
2002654012fSReza Sabdar 		 * wait for the reader.
2012654012fSReza Sabdar 		 */
2022654012fSReza Sabdar 		tlm_buffer_in_buf_timed_wait(buffers, 500);
2032654012fSReza Sabdar 
2042654012fSReza Sabdar 		buffer = tlm_buffer_out_buf(buffers, NULL);
2052654012fSReza Sabdar 		if (!buffer->tb_full) {
2062654012fSReza Sabdar 			/*
2072654012fSReza Sabdar 			 * we do not have anything from the tape yet
2082654012fSReza Sabdar 			 */
2092654012fSReza Sabdar 			return (0);
2102654012fSReza Sabdar 		}
2112654012fSReza Sabdar 
2122654012fSReza Sabdar 		current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
2132654012fSReza Sabdar 	}
2142654012fSReza Sabdar 
2152654012fSReza Sabdar 	/* Make sure we got something */
2162654012fSReza Sabdar 	if (current_size <= 0)
2172654012fSReza Sabdar 		return (NULL);
2182654012fSReza Sabdar 
2192654012fSReza Sabdar 	current_size = min(want, current_size);
2202654012fSReza Sabdar 	rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot];
2212654012fSReza Sabdar 	buffer->tb_buffer_spot += current_size;
2222654012fSReza Sabdar 	*actual_size = current_size;
2232654012fSReza Sabdar 
2242654012fSReza Sabdar 	/*
2252654012fSReza Sabdar 	 * the error flag is only sent back one time,
2262654012fSReza Sabdar 	 * since the flag refers to a previous read
2272654012fSReza Sabdar 	 * attempt, not the data in this buffer.
2282654012fSReza Sabdar 	 */
2292654012fSReza Sabdar 	*error = buffer->tb_errno;
2302654012fSReza Sabdar 
2312654012fSReza Sabdar 	return (rec);
2322654012fSReza Sabdar }
2332654012fSReza Sabdar 
2342654012fSReza Sabdar 
2352654012fSReza Sabdar /*
2362654012fSReza Sabdar  * unread a previously read buffer back to the tape buffer
2372654012fSReza Sabdar  */
2382654012fSReza Sabdar void
tlm_unget_read_buffer(tlm_buffers_t * buffers,int size)2392654012fSReza Sabdar tlm_unget_read_buffer(tlm_buffers_t *buffers, int size)
2402654012fSReza Sabdar {
2412654012fSReza Sabdar 	tlm_buffer_t *buffer;
2422654012fSReza Sabdar 	int	align_size = RECORDSIZE - 1;
2432654012fSReza Sabdar 	int	buf;
2442654012fSReza Sabdar 	int	current_size;
2452654012fSReza Sabdar 
2462654012fSReza Sabdar 	buf = buffers->tbs_buffer_out;
2472654012fSReza Sabdar 	buffer = &buffers->tbs_buffer[buf];
2482654012fSReza Sabdar 
2492654012fSReza Sabdar 	/*
2502654012fSReza Sabdar 	 * make sure the allocation is in chunks of 512 bytes
2512654012fSReza Sabdar 	 */
2522654012fSReza Sabdar 	size += align_size;
2532654012fSReza Sabdar 	size &= ~align_size;
2542654012fSReza Sabdar 
2552654012fSReza Sabdar 	current_size = min(size, buffer->tb_buffer_spot);
2562654012fSReza Sabdar 	buffer->tb_buffer_spot -= current_size;
2572654012fSReza Sabdar }
2582654012fSReza Sabdar 
2592654012fSReza Sabdar 
2602654012fSReza Sabdar /*
2612654012fSReza Sabdar  * unwrite a previously written buffer
2622654012fSReza Sabdar  */
2632654012fSReza Sabdar void
tlm_unget_write_buffer(tlm_buffers_t * buffers,int size)2642654012fSReza Sabdar tlm_unget_write_buffer(tlm_buffers_t *buffers, int size)
2652654012fSReza Sabdar {
2662654012fSReza Sabdar 	tlm_buffer_t *buffer;
2672654012fSReza Sabdar 	int	align_size = RECORDSIZE - 1;
2682654012fSReza Sabdar 	int	buf;
2692654012fSReza Sabdar 	int	current_size;
2702654012fSReza Sabdar 
2712654012fSReza Sabdar 	buf = buffers->tbs_buffer_in;
2722654012fSReza Sabdar 	buffer = &buffers->tbs_buffer[buf];
2732654012fSReza Sabdar 
2742654012fSReza Sabdar 	/*
2752654012fSReza Sabdar 	 * make sure the allocation is in chunks of 512 bytes
2762654012fSReza Sabdar 	 */
2772654012fSReza Sabdar 	size += align_size;
2782654012fSReza Sabdar 	size &= ~align_size;
2792654012fSReza Sabdar 
2802654012fSReza Sabdar 	current_size = min(size, buffer->tb_buffer_spot);
2812654012fSReza Sabdar 	buffer->tb_buffer_spot -= current_size;
2822654012fSReza Sabdar }
2832654012fSReza Sabdar 
2842654012fSReza Sabdar 
2852654012fSReza Sabdar /*
2862654012fSReza Sabdar  * build a checksum for a TAR header record
2872654012fSReza Sabdar  */
2882654012fSReza Sabdar void
tlm_build_header_checksum(tlm_tar_hdr_t * r)2892654012fSReza Sabdar tlm_build_header_checksum(tlm_tar_hdr_t *r)
2902654012fSReza Sabdar {
2912654012fSReza Sabdar 	int	i;
2922654012fSReza Sabdar 	int	sum = 0;
2932654012fSReza Sabdar 	char *c = (char *)r;
2942654012fSReza Sabdar 
2952654012fSReza Sabdar 	(void) memcpy(r->th_chksum, CHKBLANKS, strlen(CHKBLANKS));
2962654012fSReza Sabdar 	for (i = 0; i < RECORDSIZE; i++) {
2972654012fSReza Sabdar 		sum += c[i] & 0xFF;
2982654012fSReza Sabdar 	}
2992654012fSReza Sabdar 	(void) snprintf(r->th_chksum, sizeof (r->th_chksum), "%6o", sum);
3002654012fSReza Sabdar }
3012654012fSReza Sabdar 
3022654012fSReza Sabdar /*
3032654012fSReza Sabdar  * verify the tar header checksum
3042654012fSReza Sabdar  */
3052654012fSReza Sabdar int
tlm_vfy_tar_checksum(tlm_tar_hdr_t * tar_hdr)3062654012fSReza Sabdar tlm_vfy_tar_checksum(tlm_tar_hdr_t *tar_hdr)
3072654012fSReza Sabdar {
3082654012fSReza Sabdar 	int	chksum = oct_atoi(tar_hdr->th_chksum);
3092654012fSReza Sabdar 	uchar_t	*p = (uchar_t *)tar_hdr;
3102654012fSReza Sabdar 	int	sum = 0;	/* initial value of checksum */
3112654012fSReza Sabdar 	int	i;		/* loop counter */
3122654012fSReza Sabdar 
3132654012fSReza Sabdar 	/*
3142654012fSReza Sabdar 	 * compute the checksum
3152654012fSReza Sabdar 	 */
3162654012fSReza Sabdar 	for (i = 0; i < RECORDSIZE; i++) {
3172654012fSReza Sabdar 		sum += p[i] & 0xFF;
3182654012fSReza Sabdar 	}
3192654012fSReza Sabdar 
3202654012fSReza Sabdar 	if (sum == 0) {
3212654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
3222654012fSReza Sabdar 		    "should be %d, is 0", chksum);
3232654012fSReza Sabdar 		/* a zero record ==> end of tar file */
3242654012fSReza Sabdar 		return (0);
3252654012fSReza Sabdar 	}
3262654012fSReza Sabdar 
3272654012fSReza Sabdar 	/*
3282654012fSReza Sabdar 	 * subtract out the label's checksum values
3292654012fSReza Sabdar 	 * this lets us undo the old checksum "in-
3302654012fSReza Sabdar 	 * place", no need to swap blanks in and out
3312654012fSReza Sabdar 	 */
3322654012fSReza Sabdar 	for (i = 0; i < 8; i++) {
3332654012fSReza Sabdar 		sum -= 0xFF & tar_hdr->th_chksum[i];
3342654012fSReza Sabdar 	}
3352654012fSReza Sabdar 
3362654012fSReza Sabdar 	/*
3372654012fSReza Sabdar 	 * replace the old checksum field with blanks
3382654012fSReza Sabdar 	 */
3392654012fSReza Sabdar 	sum += ' ' * 8;
3402654012fSReza Sabdar 
3412654012fSReza Sabdar 	if (sum != chksum)
3422654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
3432654012fSReza Sabdar 		    "should be %d, is %d", chksum, sum);
3442654012fSReza Sabdar 
3452654012fSReza Sabdar 	return ((sum == chksum) ? 1 : -1);
3462654012fSReza Sabdar }
3472654012fSReza Sabdar 
3482654012fSReza Sabdar /*
3492654012fSReza Sabdar  * get internal scsi_sasd entry for this tape drive
3502654012fSReza Sabdar  */
3512654012fSReza Sabdar int
tlm_get_scsi_sasd_entry(int lib,int drv)3522654012fSReza Sabdar tlm_get_scsi_sasd_entry(int lib, int drv)
3532654012fSReza Sabdar {
3542654012fSReza Sabdar 	int entry;
3552654012fSReza Sabdar 	int i, n;
3562654012fSReza Sabdar 	scsi_link_t *sl;
3572654012fSReza Sabdar 	tlm_drive_t *dp;
3582654012fSReza Sabdar 
3592654012fSReza Sabdar 	entry = -1;
3602654012fSReza Sabdar 	dp = tlm_drive(lib, drv);
3612654012fSReza Sabdar 	if (!dp) {
3622654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "NULL dp for (%d.%d)", lib, drv);
3632654012fSReza Sabdar 	} else if (!dp->td_slink) {
3642654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink for (%d.%d)", lib, drv);
3652654012fSReza Sabdar 	} else if (!dp->td_slink->sl_sa) {
3662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink->sl_sa for (%d.%d)",
3672654012fSReza Sabdar 		    lib, drv);
3682654012fSReza Sabdar 	} else {
3692654012fSReza Sabdar 		/* search through the SASD table */
3702654012fSReza Sabdar 		n = sasd_dev_count();
3712654012fSReza Sabdar 		for (i = 0; i < n; i++) {
3722654012fSReza Sabdar 			sl = sasd_dev_slink(i);
3732654012fSReza Sabdar 			if (!sl)
3742654012fSReza Sabdar 				continue;
3752654012fSReza Sabdar 
3762654012fSReza Sabdar 			if (dp->td_slink->sl_sa == sl->sl_sa &&
3772654012fSReza Sabdar 			    dp->td_scsi_id == sl->sl_sid &&
3782654012fSReza Sabdar 			    dp->td_lun == sl->sl_lun) {
3792654012fSReza Sabdar 				/* all 3 variables match */
3802654012fSReza Sabdar 				entry = i;
3812654012fSReza Sabdar 				break;
3822654012fSReza Sabdar 			}
3832654012fSReza Sabdar 		}
3842654012fSReza Sabdar 	}
3852654012fSReza Sabdar 
3862654012fSReza Sabdar 	return (entry);
3872654012fSReza Sabdar }
3882654012fSReza Sabdar 
3892654012fSReza Sabdar /*
3902654012fSReza Sabdar  * get the OS device name for this tape
3912654012fSReza Sabdar  */
3922654012fSReza Sabdar char *
tlm_get_tape_name(int lib,int drv)3932654012fSReza Sabdar tlm_get_tape_name(int lib, int drv)
3942654012fSReza Sabdar {
3952654012fSReza Sabdar 	int entry;
3962654012fSReza Sabdar 
3972654012fSReza Sabdar 	entry = tlm_get_scsi_sasd_entry(lib, drv);
3982654012fSReza Sabdar 	if (entry >= 0) {
3992654012fSReza Sabdar 		sasd_drive_t *sd;
4002654012fSReza Sabdar 
4012654012fSReza Sabdar 		if ((sd = sasd_drive(entry)) != 0)
4022654012fSReza Sabdar 			return (sd->sd_name);
4032654012fSReza Sabdar 	}
4042654012fSReza Sabdar 
4052654012fSReza Sabdar 	return ("");
4062654012fSReza Sabdar }
4072654012fSReza Sabdar 
4082654012fSReza Sabdar /*
4092654012fSReza Sabdar  * create the IPC area between the reader and writer
4102654012fSReza Sabdar  */
4112654012fSReza Sabdar tlm_cmd_t *
tlm_create_reader_writer_ipc(boolean_t write,long data_transfer_size)4122654012fSReza Sabdar tlm_create_reader_writer_ipc(boolean_t write, long data_transfer_size)
4132654012fSReza Sabdar {
4142654012fSReza Sabdar 	tlm_cmd_t *cmd;
4152654012fSReza Sabdar 
4162654012fSReza Sabdar 	cmd = ndmp_malloc(sizeof (tlm_cmd_t));
4172654012fSReza Sabdar 	if (cmd == NULL)
4182654012fSReza Sabdar 		return (NULL);
4192654012fSReza Sabdar 
4202654012fSReza Sabdar 	cmd->tc_reader = TLM_BACKUP_RUN;
4212654012fSReza Sabdar 	cmd->tc_writer = TLM_BACKUP_RUN;
4222654012fSReza Sabdar 	cmd->tc_ref = 1;
4232654012fSReza Sabdar 
4242654012fSReza Sabdar 	cmd->tc_buffers = tlm_allocate_buffers(write, data_transfer_size);
4252654012fSReza Sabdar 	if (cmd->tc_buffers == NULL) {
4262654012fSReza Sabdar 		free(cmd);
4272654012fSReza Sabdar 		return (NULL);
4282654012fSReza Sabdar 	}
4292654012fSReza Sabdar 
4302654012fSReza Sabdar 	(void) mutex_init(&cmd->tc_mtx, 0, NULL);
4312654012fSReza Sabdar 	(void) cond_init(&cmd->tc_cv, 0, NULL);
4322654012fSReza Sabdar 
4332654012fSReza Sabdar 	return (cmd);
4342654012fSReza Sabdar }
4352654012fSReza Sabdar 
4362654012fSReza Sabdar /*
4372654012fSReza Sabdar  * release(destroy) the IPC between the reader and writer
4382654012fSReza Sabdar  */
4392654012fSReza Sabdar void
tlm_release_reader_writer_ipc(tlm_cmd_t * cmd)4402654012fSReza Sabdar tlm_release_reader_writer_ipc(tlm_cmd_t *cmd)
4412654012fSReza Sabdar {
4422654012fSReza Sabdar 	if (--cmd->tc_ref <= 0) {
4432654012fSReza Sabdar 		(void) mutex_lock(&cmd->tc_mtx);
4442654012fSReza Sabdar 		tlm_release_buffers(cmd->tc_buffers);
4452654012fSReza Sabdar 		(void) cond_destroy(&cmd->tc_cv);
4462654012fSReza Sabdar 		(void) mutex_unlock(&cmd->tc_mtx);
4472654012fSReza Sabdar 		(void) mutex_destroy(&cmd->tc_mtx);
4482654012fSReza Sabdar 		free(cmd);
4492654012fSReza Sabdar 	}
4502654012fSReza Sabdar }
4512654012fSReza Sabdar 
4522654012fSReza Sabdar 
4532654012fSReza Sabdar /*
4542654012fSReza Sabdar  * NDMP support begins here.
4552654012fSReza Sabdar  */
4562654012fSReza Sabdar 
4572654012fSReza Sabdar /*
4582654012fSReza Sabdar  * Initialize the file history callback functions
4592654012fSReza Sabdar  */
4602654012fSReza Sabdar lbr_fhlog_call_backs_t *
lbrlog_callbacks_init(void * cookie,path_hist_func_t log_pname_func,dir_hist_func_t log_dir_func,node_hist_func_t log_node_func)4612654012fSReza Sabdar lbrlog_callbacks_init(void *cookie, path_hist_func_t log_pname_func,
4622654012fSReza Sabdar     dir_hist_func_t log_dir_func, node_hist_func_t log_node_func)
4632654012fSReza Sabdar {
4642654012fSReza Sabdar 	lbr_fhlog_call_backs_t *p;
4652654012fSReza Sabdar 
4662654012fSReza Sabdar 	p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t));
4672654012fSReza Sabdar 	if (p == NULL)
4682654012fSReza Sabdar 		return (NULL);
4692654012fSReza Sabdar 
4702654012fSReza Sabdar 	p->fh_cookie = cookie;
4712654012fSReza Sabdar 	p->fh_logpname = (func_t)log_pname_func;
4722654012fSReza Sabdar 	p->fh_log_dir = (func_t)log_dir_func;
4732654012fSReza Sabdar 	p->fh_log_node = (func_t)log_node_func;
4742654012fSReza Sabdar 	return (p);
4752654012fSReza Sabdar }
4762654012fSReza Sabdar 
4772654012fSReza Sabdar /*
4782654012fSReza Sabdar  * Cleanup the callbacks
4792654012fSReza Sabdar  */
4802654012fSReza Sabdar void
lbrlog_callbacks_done(lbr_fhlog_call_backs_t * p)4812654012fSReza Sabdar lbrlog_callbacks_done(lbr_fhlog_call_backs_t *p)
4822654012fSReza Sabdar {
4832654012fSReza Sabdar 	if (p != NULL)
4842654012fSReza Sabdar 		(void) free((char *)p);
4852654012fSReza Sabdar }
4862654012fSReza Sabdar 
4872654012fSReza Sabdar /*
4882654012fSReza Sabdar  * Call back for file history directory info
4892654012fSReza Sabdar  */
4902654012fSReza Sabdar int
tlm_log_fhdir(tlm_job_stats_t * job_stats,char * dir,struct stat64 * stp,fs_fhandle_t * fhp)4912654012fSReza Sabdar tlm_log_fhdir(tlm_job_stats_t *job_stats, char *dir, struct stat64 *stp,
4922654012fSReza Sabdar     fs_fhandle_t *fhp)
4932654012fSReza Sabdar {
4942654012fSReza Sabdar 	int rv;
4952654012fSReza Sabdar 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
4962654012fSReza Sabdar 
4972654012fSReza Sabdar 	rv = 0;
4982654012fSReza Sabdar 	if (job_stats == NULL) {
4992654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhdir: jstat is NULL");
5002654012fSReza Sabdar 	} else if (dir == NULL) {
5012654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhdir: dir is NULL");
5022654012fSReza Sabdar 	} else if (stp == NULL) {
5032654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhdir: stp is NULL");
5042654012fSReza Sabdar 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
5052654012fSReza Sabdar 	    == NULL) {
5062654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhdir: cbp is NULL");
5072654012fSReza Sabdar 	} else if (cbp->fh_log_dir == NULL) {
5082654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhdir: callback is NULL");
5092654012fSReza Sabdar 	} else
5102654012fSReza Sabdar 		rv = (*cbp->fh_log_dir)(cbp, dir, stp, fhp);
5112654012fSReza Sabdar 
5122654012fSReza Sabdar 	return (rv);
5132654012fSReza Sabdar }
5142654012fSReza Sabdar 
5152654012fSReza Sabdar /*
5162654012fSReza Sabdar  * Call back for file history node info
5172654012fSReza Sabdar  */
5182654012fSReza Sabdar int
tlm_log_fhnode(tlm_job_stats_t * job_stats,char * dir,char * file,struct stat64 * stp,u_longlong_t off)5192654012fSReza Sabdar tlm_log_fhnode(tlm_job_stats_t *job_stats, char *dir, char *file,
5202654012fSReza Sabdar     struct stat64 *stp, u_longlong_t off)
5212654012fSReza Sabdar {
5222654012fSReza Sabdar 	int rv;
5232654012fSReza Sabdar 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
5242654012fSReza Sabdar 
5252654012fSReza Sabdar 	rv = 0;
5262654012fSReza Sabdar 	if (job_stats == NULL) {
5272654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhnode: jstat is NULL");
5282654012fSReza Sabdar 	} else if (dir == NULL) {
5292654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhnode: dir is NULL");
5302654012fSReza Sabdar 	} else if (file == NULL) {
5312654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhnode: file is NULL");
5322654012fSReza Sabdar 	} else if (stp == NULL) {
5332654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhnode: stp is NULL");
5342654012fSReza Sabdar 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
5352654012fSReza Sabdar 	    == NULL) {
5362654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhnode: cbp is NULL");
5372654012fSReza Sabdar 	} else if (cbp->fh_log_node == NULL) {
5382654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhnode: callback is NULL");
5392654012fSReza Sabdar 	} else
5402654012fSReza Sabdar 		rv = (*cbp->fh_log_node)(cbp, dir, file, stp, off);
5412654012fSReza Sabdar 
5422654012fSReza Sabdar 	return (rv);
5432654012fSReza Sabdar }
5442654012fSReza Sabdar 
5452654012fSReza Sabdar /*
5462654012fSReza Sabdar  * Call back for file history path info
5472654012fSReza Sabdar  */
5482654012fSReza Sabdar int
tlm_log_fhpath_name(tlm_job_stats_t * job_stats,char * pathname,struct stat64 * stp,u_longlong_t off)5492654012fSReza Sabdar tlm_log_fhpath_name(tlm_job_stats_t *job_stats, char *pathname,
5502654012fSReza Sabdar     struct stat64 *stp, u_longlong_t off)
5512654012fSReza Sabdar {
5522654012fSReza Sabdar 	int rv;
5532654012fSReza Sabdar 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
5542654012fSReza Sabdar 
5552654012fSReza Sabdar 	rv = 0;
5562654012fSReza Sabdar 	if (!job_stats) {
5572654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: jstat is NULL");
5582654012fSReza Sabdar 	} else if (!pathname) {
5592654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: pathname is NULL");
5602654012fSReza Sabdar 	} else if (!stp) {
5612654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: stp is NULL");
5622654012fSReza Sabdar 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
5632654012fSReza Sabdar 	    == 0) {
5642654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: cbp is NULL");
5652654012fSReza Sabdar 	} else if (!cbp->fh_logpname) {
5662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: callback is NULL");
5672654012fSReza Sabdar 	} else
5682654012fSReza Sabdar 		rv = (*cbp->fh_logpname)(cbp, pathname, stp, off);
5692654012fSReza Sabdar 
5702654012fSReza Sabdar 	return (rv);
5712654012fSReza Sabdar }
5722654012fSReza Sabdar 
5732654012fSReza Sabdar 
5742654012fSReza Sabdar /*
5752654012fSReza Sabdar  * Log call back to report the entry recovery
5762654012fSReza Sabdar  */
5772654012fSReza Sabdar int
tlm_entry_restored(tlm_job_stats_t * job_stats,char * name,int pos)5782654012fSReza Sabdar tlm_entry_restored(tlm_job_stats_t *job_stats, char *name, int pos)
5792654012fSReza Sabdar {
5802654012fSReza Sabdar 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
5812654012fSReza Sabdar 
5822654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d", name, pos);
5832654012fSReza Sabdar 
5842654012fSReza Sabdar 	if (job_stats == NULL) {
5852654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "entry_restored: jstat is NULL");
5862654012fSReza Sabdar 		return (0);
5872654012fSReza Sabdar 	}
5882654012fSReza Sabdar 	cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks;
5892654012fSReza Sabdar 	if (cbp == NULL) {
5902654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "entry_restored is NULL");
5912654012fSReza Sabdar 		return (0);
5922654012fSReza Sabdar 	}
5932654012fSReza Sabdar 	return (*cbp->fh_logpname)(cbp, name, 0, (longlong_t)pos);
5942654012fSReza Sabdar }
5952654012fSReza Sabdar /*
5962654012fSReza Sabdar  * NDMP support ends here.
5972654012fSReza Sabdar  */
5982654012fSReza Sabdar 
5992654012fSReza Sabdar /*
6002654012fSReza Sabdar  * Function: tlm_cat_path
6012654012fSReza Sabdar  * Concatenates two path names
6022654012fSReza Sabdar  * or directory name and file name
6032654012fSReza Sabdar  * into a buffer passed by the caller. A slash
6042654012fSReza Sabdar  * is inserted if required. Buffer is assumed
6052654012fSReza Sabdar  * to hold PATH_MAX characters.
6062654012fSReza Sabdar  *
6072654012fSReza Sabdar  * Parameters:
6082654012fSReza Sabdar  *	char *buf	- buffer to write new dir/name string
6092654012fSReza Sabdar  *	char *dir	- directory name
6102654012fSReza Sabdar  *	char *name	- file name
6112654012fSReza Sabdar  *
6122654012fSReza Sabdar  * Returns:
6132654012fSReza Sabdar  *	TRUE		- No errors. buf contains the dir/name string
6142654012fSReza Sabdar  *	FALSE		- Error. buf is not modified.
6152654012fSReza Sabdar  */
6162654012fSReza Sabdar boolean_t
tlm_cat_path(char * buf,char * dir,char * name)6172654012fSReza Sabdar tlm_cat_path(char *buf, char *dir, char *name)
6182654012fSReza Sabdar {
6192654012fSReza Sabdar 	char *fmt;
6202654012fSReza Sabdar 	int dirlen = strlen(dir);
6212654012fSReza Sabdar 	int filelen = strlen(name);
6222654012fSReza Sabdar 
6232654012fSReza Sabdar 	if ((dirlen + filelen + 1) >= PATH_MAX) {
6242654012fSReza Sabdar 		return (FALSE);
6252654012fSReza Sabdar 	}
6262654012fSReza Sabdar 
6272654012fSReza Sabdar 	if (*dir == '\0' || *name == '\0' || dir[dirlen - 1] == '/' ||
6282654012fSReza Sabdar 	    *name == '/') {
6292654012fSReza Sabdar 		fmt = "%s%s";
6302654012fSReza Sabdar 	} else {
6312654012fSReza Sabdar 		fmt = "%s/%s";
6322654012fSReza Sabdar 	}
6332654012fSReza Sabdar 
6342654012fSReza Sabdar 	/* check for ".../" and "/...." */
6352654012fSReza Sabdar 	if ((dirlen > 0) && (dir[dirlen - 1] == '/') && (*name == '/'))
6362654012fSReza Sabdar 		name += strspn(name, "/");
6372654012fSReza Sabdar 
6382654012fSReza Sabdar 	/* LINTED variable format */
6392654012fSReza Sabdar 	(void) snprintf(buf, TLM_MAX_PATH_NAME, fmt, dir, name);
6402654012fSReza Sabdar 
6412654012fSReza Sabdar 	return (TRUE);
6422654012fSReza Sabdar }
6432654012fSReza Sabdar 
6442654012fSReza Sabdar /*
6452654012fSReza Sabdar  * Get the checkpoint (snapshot) creation time.
6462654012fSReza Sabdar  * This is necessary to check for checkpoints not being stale.
6472654012fSReza Sabdar  */
6482654012fSReza Sabdar int
tlm_get_chkpnt_time(char * path,int auto_checkpoint,time_t * tp,char * jname)6492654012fSReza Sabdar tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname)
6502654012fSReza Sabdar {
6512654012fSReza Sabdar 	char volname[TLM_VOLNAME_MAX_LENGTH];
6522654012fSReza Sabdar 	char chk_name[PATH_MAX];
6532654012fSReza Sabdar 	char *cp_nm;
6542654012fSReza Sabdar 
6552654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "path [%s] auto_checkpoint: %d",
6562654012fSReza Sabdar 	    path, auto_checkpoint);
6572654012fSReza Sabdar 
6582654012fSReza Sabdar 	if (path == NULL || *path == '\0' || tp == NULL)
6592654012fSReza Sabdar 		return (-1);
6602654012fSReza Sabdar 
6612654012fSReza Sabdar 	if (get_zfsvolname(volname, TLM_VOLNAME_MAX_LENGTH,
6622654012fSReza Sabdar 	    path) == -1)
6632654012fSReza Sabdar 		return (-1);
6642654012fSReza Sabdar 
6652654012fSReza Sabdar 	if (auto_checkpoint) {
6662654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "volname [%s]", volname);
6678c4f9701SJanice Chang 		(void) snprintf(chk_name, PATH_MAX, "%s", jname);
6682654012fSReza Sabdar 		return (chkpnt_creationtime_bypattern(volname, chk_name, tp));
6692654012fSReza Sabdar 	}
6702654012fSReza Sabdar 	cp_nm = strchr(volname, '@');
6712654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "volname [%s] cp_nm [%s]", volname, cp_nm);
6722654012fSReza Sabdar 
6732654012fSReza Sabdar 	return (chkpnt_creationtime_bypattern(volname, cp_nm, tp));
6742654012fSReza Sabdar }
6752654012fSReza Sabdar 
6762654012fSReza Sabdar /*
6772654012fSReza Sabdar  * Release an array of pointers and the pointers themselves.
6782654012fSReza Sabdar  */
6792654012fSReza Sabdar void
tlm_release_list(char ** lpp)6802654012fSReza Sabdar tlm_release_list(char **lpp)
6812654012fSReza Sabdar {
6822654012fSReza Sabdar 	char **save;
6832654012fSReza Sabdar 
6842654012fSReza Sabdar 	if ((save = lpp) == 0)
6852654012fSReza Sabdar 		return;
6862654012fSReza Sabdar 
6872654012fSReza Sabdar 	while (*lpp)
6882654012fSReza Sabdar 		free(*lpp++);
6892654012fSReza Sabdar 
6902654012fSReza Sabdar 	free(save);
6912654012fSReza Sabdar }
6922654012fSReza Sabdar 
6932654012fSReza Sabdar /*
6942654012fSReza Sabdar  * Print the list of array of strings in the backup log
6952654012fSReza Sabdar  */
6962654012fSReza Sabdar void
tlm_log_list(char * title,char ** lpp)6972654012fSReza Sabdar tlm_log_list(char *title, char **lpp)
6982654012fSReza Sabdar {
6992654012fSReza Sabdar 	int i;
7002654012fSReza Sabdar 
7012654012fSReza Sabdar 	if (!lpp)
7022654012fSReza Sabdar 		return;
7032654012fSReza Sabdar 
7042654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "%s:", title);
7052654012fSReza Sabdar 
7062654012fSReza Sabdar 	for (i = 0; *lpp; lpp++, i++)
7072654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "%d: [%s]", i, *lpp);
7082654012fSReza Sabdar }
7092654012fSReza Sabdar 
7102654012fSReza Sabdar /*
7112654012fSReza Sabdar  * Insert the backup snapshot name into the path.
7122654012fSReza Sabdar  *
7132654012fSReza Sabdar  * Input:
7148c4f9701SJanice Chang  * 	name: Original path name.
7152654012fSReza Sabdar  *
7162654012fSReza Sabdar  * Output:
7178c4f9701SJanice Chang  * 	name: Original name modified to include a snapshot.
7182654012fSReza Sabdar  *
7192654012fSReza Sabdar  * Returns:
7208c4f9701SJanice Chang  * 	Original name modified to include a snapshot.
7212654012fSReza Sabdar  */
7222654012fSReza Sabdar char *
tlm_build_snapshot_name(char * name,char * sname,char * jname)7232654012fSReza Sabdar tlm_build_snapshot_name(char *name, char *sname, char *jname)
7242654012fSReza Sabdar {
7252654012fSReza Sabdar 	zfs_handle_t *zhp;
7262654012fSReza Sabdar 	char *rest;
727*9adfa60dSMatthew Ahrens 	char volname[ZFS_MAX_DATASET_NAME_LEN];
7282654012fSReza Sabdar 	char mountpoint[PATH_MAX];
7292654012fSReza Sabdar 
730*9adfa60dSMatthew Ahrens 	if (get_zfsvolname(volname, ZFS_MAX_DATASET_NAME_LEN, name) == -1)
7312654012fSReza Sabdar 		goto notzfs;
7322654012fSReza Sabdar 
7332654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
7342654012fSReza Sabdar 	if ((zlibh == NULL) ||
7352654012fSReza Sabdar 	    (zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == NULL) {
7362654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
7372654012fSReza Sabdar 		goto notzfs;
7382654012fSReza Sabdar 	}
7392654012fSReza Sabdar 
7402654012fSReza Sabdar 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, PATH_MAX, NULL,
7412654012fSReza Sabdar 	    NULL, 0, B_FALSE) != 0) {
7422654012fSReza Sabdar 		zfs_close(zhp);
7432654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
7442654012fSReza Sabdar 		goto notzfs;
7452654012fSReza Sabdar 	}
7462654012fSReza Sabdar 
7472654012fSReza Sabdar 	zfs_close(zhp);
7482654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
7492654012fSReza Sabdar 
7502654012fSReza Sabdar 	rest = name + strlen(mountpoint);
7518c4f9701SJanice Chang 	(void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint,
7522654012fSReza Sabdar 	    TLM_SNAPSHOT_DIR, jname, rest);
7532654012fSReza Sabdar 
7542654012fSReza Sabdar 	return (sname);
7552654012fSReza Sabdar 
7562654012fSReza Sabdar notzfs:
7572654012fSReza Sabdar 	(void) strlcpy(sname, name, TLM_MAX_PATH_NAME);
7582654012fSReza Sabdar 	return (sname);
7592654012fSReza Sabdar }
7602654012fSReza Sabdar 
7612654012fSReza Sabdar /*
7622654012fSReza Sabdar  * Remove the checkpoint from a path name.
7632654012fSReza Sabdar  *
7642654012fSReza Sabdar  * Input:
7652654012fSReza Sabdar  * 	name: Full pathname with checkpoint embeded.
7662654012fSReza Sabdar  *
7672654012fSReza Sabdar  * Output:
7682654012fSReza Sabdar  * 	unchkp_name: real pathname with no checkpoint.
7692654012fSReza Sabdar  *
7702654012fSReza Sabdar  * Returns:
7712654012fSReza Sabdar  *	Pointer to the un-checkpointed path.
7722654012fSReza Sabdar  */
7732654012fSReza Sabdar char *
tlm_remove_checkpoint(char * name,char * unchkp_name)7742654012fSReza Sabdar tlm_remove_checkpoint(char *name, char *unchkp_name)
7752654012fSReza Sabdar {
7762654012fSReza Sabdar 	char *cp;
7772654012fSReza Sabdar 	int i;
7782654012fSReza Sabdar 	int plen;
7792654012fSReza Sabdar 
7802654012fSReza Sabdar 	unchkp_name[0] = name[0];
7812654012fSReza Sabdar 	plen = strlen(TLM_SNAPSHOT_PREFIX);
7822654012fSReza Sabdar 	for (i = 1; i <= TLM_VOLNAME_MAX_LENGTH + 1; i++) {
7832654012fSReza Sabdar 		switch (name[i]) {
7842654012fSReza Sabdar 		case '.':
7852654012fSReza Sabdar 			if (strncmp(&name[i], TLM_SNAPSHOT_PREFIX,
7862654012fSReza Sabdar 			    plen) == 0) {
7872654012fSReza Sabdar 				unchkp_name[i] = '\0';
7882654012fSReza Sabdar 				i += plen;
7892654012fSReza Sabdar 				if (name[i] == '\0') {
7902654012fSReza Sabdar 					/*
7912654012fSReza Sabdar 					 * name == "/v1.chkpnt"
7922654012fSReza Sabdar 					 */
7932654012fSReza Sabdar 					return (unchkp_name);
7942654012fSReza Sabdar 				}
7952654012fSReza Sabdar 				if ((cp = strchr(&name[++i], '/')) != NULL) {
7962654012fSReza Sabdar 					(void) strlcat(unchkp_name, cp,
7972654012fSReza Sabdar 					    TLM_VOLNAME_MAX_LENGTH + 1);
7982654012fSReza Sabdar 				}
7992654012fSReza Sabdar 				return (unchkp_name);
8002654012fSReza Sabdar 			} else {
8012654012fSReza Sabdar 				unchkp_name[i] = name[i];
8022654012fSReza Sabdar 			}
8032654012fSReza Sabdar 			break;
8042654012fSReza Sabdar 		case '/':
8052654012fSReza Sabdar 			return (name);
8062654012fSReza Sabdar 		case 0:
8072654012fSReza Sabdar 			return (name);
8082654012fSReza Sabdar 		default:
8092654012fSReza Sabdar 			unchkp_name[i] = name[i];
8102654012fSReza Sabdar 			break;
8112654012fSReza Sabdar 		}
8122654012fSReza Sabdar 	}
8132654012fSReza Sabdar 	return (name);
8142654012fSReza Sabdar }
8152654012fSReza Sabdar 
8162654012fSReza Sabdar /*
8172654012fSReza Sabdar  * see if we should exclude this file.
8182654012fSReza Sabdar  */
8192654012fSReza Sabdar boolean_t
tlm_is_excluded(char * dir,char * name,char ** excl_files)8202654012fSReza Sabdar tlm_is_excluded(char *dir, char *name, char **excl_files)
8212654012fSReza Sabdar {
8222654012fSReza Sabdar 	int	i;
8232654012fSReza Sabdar 	char	full_name[TLM_MAX_PATH_NAME];
8242654012fSReza Sabdar 
8252654012fSReza Sabdar 	if (!dir || !name || !excl_files)
8262654012fSReza Sabdar 		return (FALSE);
8272654012fSReza Sabdar 
8282654012fSReza Sabdar 	if (!tlm_cat_path(full_name, dir, name)) {
8292654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]",
8302654012fSReza Sabdar 		    dir, name);
8312654012fSReza Sabdar 		return (FALSE);
8322654012fSReza Sabdar 	}
8332654012fSReza Sabdar 	for (i = 0; excl_files[i] != 0; i++) {
8342654012fSReza Sabdar 		if (match(excl_files[i], full_name)) {
8352654012fSReza Sabdar 			return (TRUE);
8362654012fSReza Sabdar 		}
8372654012fSReza Sabdar 	}
8382654012fSReza Sabdar 	return (FALSE);
8392654012fSReza Sabdar }
8402654012fSReza Sabdar 
8412654012fSReza Sabdar /*
8422654012fSReza Sabdar  * Check if the path is too long
8432654012fSReza Sabdar  */
8442654012fSReza Sabdar boolean_t
tlm_is_too_long(int checkpointed,char * dir,char * nm)8452654012fSReza Sabdar tlm_is_too_long(int checkpointed, char *dir, char *nm)
8462654012fSReza Sabdar {
8472654012fSReza Sabdar 	int nlen, tot;
8482654012fSReza Sabdar 
8492654012fSReza Sabdar 	tot = 0;
8502654012fSReza Sabdar 	if (dir)
8512654012fSReza Sabdar 		tot += strlen(dir);
8522654012fSReza Sabdar 	if (checkpointed)
8532654012fSReza Sabdar 		tot += strlen(TLM_SNAPSHOT_DIR) + 1;
8542654012fSReza Sabdar 	if (nm) {
8552654012fSReza Sabdar 		if ((nlen = strlen(nm)) > 0)
8562654012fSReza Sabdar 			tot += nlen + 1;
8572654012fSReza Sabdar 	}
8582654012fSReza Sabdar 	return ((tot >= PATH_MAX) ? TRUE : FALSE);
8592654012fSReza Sabdar }
8602654012fSReza Sabdar 
8612654012fSReza Sabdar /*
8622654012fSReza Sabdar  * Get the data offset of inside the buffer
8632654012fSReza Sabdar  */
8642654012fSReza Sabdar longlong_t
tlm_get_data_offset(tlm_cmd_t * lcmds)8652654012fSReza Sabdar tlm_get_data_offset(tlm_cmd_t *lcmds)
8662654012fSReza Sabdar {
8672654012fSReza Sabdar 	if (!lcmds)
8682654012fSReza Sabdar 		return (0LL);
8692654012fSReza Sabdar 
8702654012fSReza Sabdar 	return (lcmds->tc_buffers->tbs_offset);
8712654012fSReza Sabdar }
8722654012fSReza Sabdar 
8732654012fSReza Sabdar /*
8742654012fSReza Sabdar  * Enable the barcode capability on the library
8752654012fSReza Sabdar  */
8762654012fSReza Sabdar void
tlm_enable_barcode(int l)8772654012fSReza Sabdar tlm_enable_barcode(int l)
8782654012fSReza Sabdar {
8792654012fSReza Sabdar 	tlm_library_t *lp;
8802654012fSReza Sabdar 
8812654012fSReza Sabdar 	if ((lp = tlm_library(l))) {
8822654012fSReza Sabdar 		lp->tl_capability_barcodes = TRUE;
8832654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
8842654012fSReza Sabdar 		    "Barcode capability on library %d enabled.", l);
8852654012fSReza Sabdar 	}
8862654012fSReza Sabdar }
8872654012fSReza Sabdar 
8882654012fSReza Sabdar /*
8892654012fSReza Sabdar  * SASD SCSI support
8902654012fSReza Sabdar  */
8912654012fSReza Sabdar static scsi_adapter_t my_sa;
8922654012fSReza Sabdar static int sasd_drive_count = 0;
8932654012fSReza Sabdar static scsi_sasd_drive_t *scsi_sasd_drives[128];
8942654012fSReza Sabdar 
8952654012fSReza Sabdar /*
8962654012fSReza Sabdar  * Count of SCSI devices
8972654012fSReza Sabdar  */
8982654012fSReza Sabdar int
sasd_dev_count(void)8992654012fSReza Sabdar sasd_dev_count(void)
9002654012fSReza Sabdar {
9012654012fSReza Sabdar 	return (sasd_drive_count);
9022654012fSReza Sabdar }
9032654012fSReza Sabdar 
9042654012fSReza Sabdar /*
9052654012fSReza Sabdar  * Return the SCSI device name
9062654012fSReza Sabdar  */
9072654012fSReza Sabdar char *
sasd_slink_name(scsi_link_t * slink)9082654012fSReza Sabdar sasd_slink_name(scsi_link_t *slink)
9092654012fSReza Sabdar {
9102654012fSReza Sabdar 	int i;
9112654012fSReza Sabdar 
9122654012fSReza Sabdar 	for (i = 0; i < sasd_drive_count; i++) {
9132654012fSReza Sabdar 		if (&scsi_sasd_drives[i]->ss_slink == slink)
9142654012fSReza Sabdar 			return (scsi_sasd_drives[i]->ss_sd.sd_name);
9152654012fSReza Sabdar 	}
9162654012fSReza Sabdar 	return (NULL);
9172654012fSReza Sabdar }
9182654012fSReza Sabdar 
9192654012fSReza Sabdar /*
9202654012fSReza Sabdar  * Return the SCSI drive structure
9212654012fSReza Sabdar  */
9222654012fSReza Sabdar sasd_drive_t *
sasd_slink_drive(scsi_link_t * slink)9232654012fSReza Sabdar sasd_slink_drive(scsi_link_t *slink)
9242654012fSReza Sabdar {
9252654012fSReza Sabdar 	int i;
9262654012fSReza Sabdar 
9272654012fSReza Sabdar 	for (i = 0; i < sasd_drive_count; i++) {
9282654012fSReza Sabdar 		if (&scsi_sasd_drives[i]->ss_slink == slink)
9292654012fSReza Sabdar 			return (&scsi_sasd_drives[i]->ss_sd);
9302654012fSReza Sabdar 	}
9312654012fSReza Sabdar 	return (NULL);
9322654012fSReza Sabdar }
9332654012fSReza Sabdar 
9342654012fSReza Sabdar /*
9352654012fSReza Sabdar  * Return the SCSI link pointer for the given index
9362654012fSReza Sabdar  */
9372654012fSReza Sabdar scsi_link_t *
sasd_dev_slink(int entry)9382654012fSReza Sabdar sasd_dev_slink(int entry)
9392654012fSReza Sabdar {
9402654012fSReza Sabdar 	scsi_link_t *rv;
9412654012fSReza Sabdar 
9422654012fSReza Sabdar 	if (entry >= 0 && entry < sasd_drive_count)
9432654012fSReza Sabdar 		rv = &scsi_sasd_drives[entry]->ss_slink;
9442654012fSReza Sabdar 	else
9452654012fSReza Sabdar 		rv = NULL;
9462654012fSReza Sabdar 
9472654012fSReza Sabdar 	return (rv);
9482654012fSReza Sabdar }
9492654012fSReza Sabdar 
9502654012fSReza Sabdar /*
9512654012fSReza Sabdar  * Return the SCSI drive for the given index
9522654012fSReza Sabdar  */
9532654012fSReza Sabdar sasd_drive_t *
sasd_drive(int entry)9542654012fSReza Sabdar sasd_drive(int entry)
9552654012fSReza Sabdar {
9562654012fSReza Sabdar 	sasd_drive_t *rv;
9572654012fSReza Sabdar 
9582654012fSReza Sabdar 	if (entry >= 0 && entry < sasd_drive_count)
9592654012fSReza Sabdar 		rv = &scsi_sasd_drives[entry]->ss_sd;
9602654012fSReza Sabdar 	else
9612654012fSReza Sabdar 		rv = NULL;
9622654012fSReza Sabdar 
9632654012fSReza Sabdar 	return (rv);
9642654012fSReza Sabdar }
9652654012fSReza Sabdar 
9662654012fSReza Sabdar /*
9672654012fSReza Sabdar  * Attach the SCSI device by updating the structures
9682654012fSReza Sabdar  */
9692654012fSReza Sabdar void
scsi_sasd_attach(scsi_adapter_t * sa,int sid,int lun,char * name,int type)9702654012fSReza Sabdar scsi_sasd_attach(scsi_adapter_t *sa, int sid, int lun, char *name,
9712654012fSReza Sabdar     int type)
9722654012fSReza Sabdar {
9732654012fSReza Sabdar 	scsi_link_t *sl, *next;
9742654012fSReza Sabdar 	scsi_sasd_drive_t *ssd;
9752654012fSReza Sabdar 
9762654012fSReza Sabdar 	ssd = ndmp_malloc(sizeof (scsi_sasd_drive_t));
9772654012fSReza Sabdar 	if (ssd == NULL)
9782654012fSReza Sabdar 		return;
9792654012fSReza Sabdar 
9802654012fSReza Sabdar 	scsi_sasd_drives[sasd_drive_count++] = ssd;
9812654012fSReza Sabdar 
9822654012fSReza Sabdar 	switch (type) {
9832654012fSReza Sabdar 	case DTYPE_CHANGER:
9842654012fSReza Sabdar 		(void) snprintf(ssd->ss_sd.sd_name,
9852654012fSReza Sabdar 		    sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_CHANGER_DIR,
9862654012fSReza Sabdar 		    name);
9872654012fSReza Sabdar 		break;
9882654012fSReza Sabdar 	case DTYPE_SEQUENTIAL:
9892654012fSReza Sabdar 		(void) snprintf(ssd->ss_sd.sd_name,
9902654012fSReza Sabdar 		    sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_TAPE_DIR, name);
9912654012fSReza Sabdar 		break;
9922654012fSReza Sabdar 	}
9932654012fSReza Sabdar 
9942654012fSReza Sabdar 	sl = &ssd->ss_slink;
9952654012fSReza Sabdar 	sl->sl_type = type;
9962654012fSReza Sabdar 	sl->sl_sa = sa;
9972654012fSReza Sabdar 	sl->sl_lun = lun;
9982654012fSReza Sabdar 	sl->sl_sid = sid;
9992654012fSReza Sabdar 	sl->sl_requested_max_active = 1;
10002654012fSReza Sabdar 
10012654012fSReza Sabdar 	/* Insert slink */
10022654012fSReza Sabdar 	next = sa->sa_link_head.sl_next;
10032654012fSReza Sabdar 	sa->sa_link_head.sl_next = sl;
10042654012fSReza Sabdar 	sl->sl_next = next;
10052654012fSReza Sabdar }
10062654012fSReza Sabdar 
10072654012fSReza Sabdar /*
10082654012fSReza Sabdar  * Go through the attached devices and detect the tape
10092654012fSReza Sabdar  * and robot by checking the /dev entries
10102654012fSReza Sabdar  */
10112654012fSReza Sabdar int
probe_scsi(void)10122654012fSReza Sabdar probe_scsi(void)
10132654012fSReza Sabdar {
10142654012fSReza Sabdar 	DIR *dirp;
10152654012fSReza Sabdar 	struct dirent *dp;
10162654012fSReza Sabdar 	scsi_adapter_t *sa = &my_sa;
10172654012fSReza Sabdar 	char *p;
10182654012fSReza Sabdar 	int lun = 0;
10192654012fSReza Sabdar 	int sid = 0;
10201e05b03fSJanice Chang 	char *drive_type;
10212654012fSReza Sabdar 
10222654012fSReza Sabdar 	/* Initialize the scsi adapter link */
10232654012fSReza Sabdar 	sa->sa_link_head.sl_next = &sa->sa_link_head;
10242654012fSReza Sabdar 
10252654012fSReza Sabdar 	/* Scan for the changer */
10262654012fSReza Sabdar 	dirp = opendir(SCSI_CHANGER_DIR);
10272654012fSReza Sabdar 	if (dirp == NULL) {
10282654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
10292654012fSReza Sabdar 		    "Changer directory read error %s", SCSI_CHANGER_DIR);
10302654012fSReza Sabdar 	} else {
10312654012fSReza Sabdar 		while ((dp = readdir(dirp)) != NULL) {
10322654012fSReza Sabdar 			if ((strcmp(dp->d_name, ".") == 0) ||
10332654012fSReza Sabdar 			    (strcmp(dp->d_name, "..") == 0))
10342654012fSReza Sabdar 				continue;
10352654012fSReza Sabdar 
10362654012fSReza Sabdar 			if ((p = strchr(dp->d_name, 'd')) != NULL) {
10372654012fSReza Sabdar 				lun = atoi(++p);
10382654012fSReza Sabdar 				p = strchr(dp->d_name, 't');
10392654012fSReza Sabdar 				sid = atoi(++p);
10402654012fSReza Sabdar 			}
10412654012fSReza Sabdar 			else
10422654012fSReza Sabdar 				sid = atoi(dp->d_name);
10432654012fSReza Sabdar 
10442654012fSReza Sabdar 			scsi_sasd_attach(sa, 0, lun, dp->d_name,
10452654012fSReza Sabdar 			    DTYPE_CHANGER);
10462654012fSReza Sabdar 		}
10472654012fSReza Sabdar 		(void) closedir(dirp);
10482654012fSReza Sabdar 	}
10492654012fSReza Sabdar 
10502654012fSReza Sabdar 	/* Scan for tape drives */
10512654012fSReza Sabdar 	dirp = opendir(SCSI_TAPE_DIR);
10522654012fSReza Sabdar 	if (dirp == NULL) {
10532654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG,
10542654012fSReza Sabdar 		    "Tape directory read error %s", SCSI_TAPE_DIR);
10552654012fSReza Sabdar 	} else {
10561e05b03fSJanice Chang 		drive_type = ndmpd_get_prop(NDMP_DRIVE_TYPE);
10571e05b03fSJanice Chang 
10581e05b03fSJanice Chang 		if ((strcasecmp(drive_type, "sysv") != 0) &&
10591e05b03fSJanice Chang 		    (strcasecmp(drive_type, "bsd") != 0)) {
10601e05b03fSJanice Chang 			NDMP_LOG(LOG_ERR, "Invalid ndmpd/drive-type value. "
10611e05b03fSJanice Chang 			    "Valid values are 'sysv' and 'bsd'.");
10621e05b03fSJanice Chang 			return (-1);
10631e05b03fSJanice Chang 		}
10641e05b03fSJanice Chang 
10652654012fSReza Sabdar 		while ((dp = readdir(dirp)) != NULL) {
10662654012fSReza Sabdar 			if ((strcmp(dp->d_name, ".") == 0) ||
10672654012fSReza Sabdar 			    (strcmp(dp->d_name, "..") == 0))
10682654012fSReza Sabdar 				continue;
10692654012fSReza Sabdar 
10702654012fSReza Sabdar 			/* Skip special modes */
10711e05b03fSJanice Chang 			if (strpbrk(dp->d_name, "chlmu") != NULL)
10722654012fSReza Sabdar 				continue;
10732654012fSReza Sabdar 
10742654012fSReza Sabdar 			/* Pick the non-rewind device */
10752654012fSReza Sabdar 			if (strchr(dp->d_name, 'n') == NULL)
10762654012fSReza Sabdar 				continue;
10772654012fSReza Sabdar 
10781e05b03fSJanice Chang 			if (strcasecmp(drive_type, "sysv") == 0) {
10791e05b03fSJanice Chang 				if (strchr(dp->d_name, 'b') != NULL)
10801e05b03fSJanice Chang 					continue;
10811e05b03fSJanice Chang 			} else if (strcasecmp(drive_type, "bsd") == 0) {
10821e05b03fSJanice Chang 				if (strchr(dp->d_name, 'b') == NULL)
10831e05b03fSJanice Chang 					continue;
10841e05b03fSJanice Chang 			}
10851e05b03fSJanice Chang 
10862654012fSReza Sabdar 			sid = atoi(dp->d_name);
10872654012fSReza Sabdar 
10882654012fSReza Sabdar 			/*
10892654012fSReza Sabdar 			 * SCSI ID should match with the ID of the device
10902654012fSReza Sabdar 			 * (will be checked by SCSI get elements page later)
10912654012fSReza Sabdar 			 */
10922654012fSReza Sabdar 			scsi_sasd_attach(sa, sid, 0, dp->d_name,
10932654012fSReza Sabdar 			    DTYPE_SEQUENTIAL);
10942654012fSReza Sabdar 		}
10952654012fSReza Sabdar 		(void) closedir(dirp);
10962654012fSReza Sabdar 	}
10972654012fSReza Sabdar 
10982654012fSReza Sabdar 	return (0);
10992654012fSReza Sabdar }
11002654012fSReza Sabdar 
11012654012fSReza Sabdar /*
11022654012fSReza Sabdar  * Get the SCSI device type (tape, robot)
11032654012fSReza Sabdar  */
11042654012fSReza Sabdar /*ARGSUSED*/
11052654012fSReza Sabdar int
scsi_get_devtype(char * adapter,int sid,int lun)11062654012fSReza Sabdar scsi_get_devtype(char *adapter, int sid, int lun)
11072654012fSReza Sabdar {
11082654012fSReza Sabdar 	int rv;
11092654012fSReza Sabdar 	scsi_adapter_t *sa = &my_sa;
11102654012fSReza Sabdar 	scsi_link_t *sl, *sh;
11112654012fSReza Sabdar 
11122654012fSReza Sabdar 	rv = -1;
11132654012fSReza Sabdar 	sh = &sa->sa_link_head;
11142654012fSReza Sabdar 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
11152654012fSReza Sabdar 		if (sl->sl_sid == sid && sl->sl_lun == lun)
11162654012fSReza Sabdar 			rv = sl->sl_type;
11172654012fSReza Sabdar 
11182654012fSReza Sabdar 	return (rv);
11192654012fSReza Sabdar }
11202654012fSReza Sabdar 
11212654012fSReza Sabdar 
11222654012fSReza Sabdar /*
11232654012fSReza Sabdar  * Check if the SCSI device exists
11242654012fSReza Sabdar  */
11252654012fSReza Sabdar /*ARGSUSED*/
11262654012fSReza Sabdar int
scsi_dev_exists(char * adapter,int sid,int lun)11272654012fSReza Sabdar scsi_dev_exists(char *adapter, int sid, int lun)
11282654012fSReza Sabdar {
11292654012fSReza Sabdar 	scsi_adapter_t *sa = &my_sa;
11302654012fSReza Sabdar 	scsi_link_t *sl, *sh;
11312654012fSReza Sabdar 
11322654012fSReza Sabdar 	sh = &sa->sa_link_head;
11332654012fSReza Sabdar 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
11342654012fSReza Sabdar 		if (sl->sl_sid == sid && sl->sl_lun == lun)
11352654012fSReza Sabdar 			return (1);
11362654012fSReza Sabdar 	return (0);
11372654012fSReza Sabdar }
11382654012fSReza Sabdar 
11392654012fSReza Sabdar 
11402654012fSReza Sabdar /*
11412654012fSReza Sabdar  * Count of SCSI adapters
11422654012fSReza Sabdar  */
11432654012fSReza Sabdar int
scsi_get_adapter_count(void)11442654012fSReza Sabdar scsi_get_adapter_count(void)
11452654012fSReza Sabdar {
11462654012fSReza Sabdar 	/* Currently support one adapter only */
11472654012fSReza Sabdar 	return (1);
11482654012fSReza Sabdar }
11492654012fSReza Sabdar 
11502654012fSReza Sabdar /*
11512654012fSReza Sabdar  * Return the SCSI adapter structure
11522654012fSReza Sabdar  */
11532654012fSReza Sabdar /*ARGSUSED*/
11542654012fSReza Sabdar scsi_adapter_t *
scsi_get_adapter(int adapter)11552654012fSReza Sabdar scsi_get_adapter(int adapter)
11562654012fSReza Sabdar {
11572654012fSReza Sabdar 	return (&my_sa);
11582654012fSReza Sabdar }
11592654012fSReza Sabdar 
11602654012fSReza Sabdar /*
11612654012fSReza Sabdar  * IOCTL wrapper with retries
11622654012fSReza Sabdar  */
11632654012fSReza Sabdar int
tlm_ioctl(int fd,int cmd,void * data)11642654012fSReza Sabdar tlm_ioctl(int fd, int cmd, void *data)
11652654012fSReza Sabdar {
11662654012fSReza Sabdar 	int retries = 0;
11672654012fSReza Sabdar 
11682654012fSReza Sabdar 	NDMP_LOG(LOG_DEBUG, "tlm_ioctl fd %d cmd %d", fd, cmd);
11692654012fSReza Sabdar 	if (fd == 0 || data == NULL)
11702654012fSReza Sabdar 		return (EINVAL);
11712654012fSReza Sabdar 
11722654012fSReza Sabdar 	do {
11732654012fSReza Sabdar 		if (ioctl(fd, cmd, data) == 0)
11742654012fSReza Sabdar 			break;
11752654012fSReza Sabdar 
11762654012fSReza Sabdar 		if (errno != EIO && errno != 0) {
11772654012fSReza Sabdar 			NDMP_LOG(LOG_ERR,
11782654012fSReza Sabdar 			    "Failed to send command to device: %m.");
11792654012fSReza Sabdar 			NDMP_LOG(LOG_DEBUG, "IOCTL error %d", errno);
11802654012fSReza Sabdar 			return (errno);
11812654012fSReza Sabdar 		}
11822654012fSReza Sabdar 		(void) sleep(1);
11832654012fSReza Sabdar 	} while (retries++ < MAXIORETRY);
11842654012fSReza Sabdar 
11852654012fSReza Sabdar 	return (0);
11862654012fSReza Sabdar }
11872654012fSReza Sabdar 
11882654012fSReza Sabdar /*
11892654012fSReza Sabdar  * Checkpoint or snapshot calls
11902654012fSReza Sabdar  */
11912654012fSReza Sabdar 
11922654012fSReza Sabdar /*
11932654012fSReza Sabdar  * Get the snapshot creation time
11942654012fSReza Sabdar  */
11952654012fSReza Sabdar int
chkpnt_creationtime_bypattern(char * volname,char * pattern,time_t * tp)11962654012fSReza Sabdar chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp)
11972654012fSReza Sabdar {
11982654012fSReza Sabdar 	char chk_name[PATH_MAX];
11992654012fSReza Sabdar 	zfs_handle_t *zhp;
12002654012fSReza Sabdar 	char *p;
12012654012fSReza Sabdar 
12022654012fSReza Sabdar 	if (!volname || !*volname)
12032654012fSReza Sabdar 		return (-1);
12042654012fSReza Sabdar 
12052654012fSReza Sabdar 	/* Should also return -1 if checkpoint not enabled */
12062654012fSReza Sabdar 
12072654012fSReza Sabdar 	/* Remove the leading slash */
12082654012fSReza Sabdar 	p = volname;
12092654012fSReza Sabdar 	while (*p == '/')
12102654012fSReza Sabdar 		p++;
12112654012fSReza Sabdar 
12122654012fSReza Sabdar 	(void) strlcpy(chk_name, p, PATH_MAX);
12132654012fSReza Sabdar 	(void) strlcat(chk_name, "@", PATH_MAX);
12142654012fSReza Sabdar 	(void) strlcat(chk_name, pattern, PATH_MAX);
12152654012fSReza Sabdar 
12162654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
12172654012fSReza Sabdar 	if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_DATASET)) == NULL) {
12182654012fSReza Sabdar 		NDMP_LOG(LOG_DEBUG, "chkpnt_creationtime: open %s failed",
12192654012fSReza Sabdar 		    chk_name);
12202654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
12212654012fSReza Sabdar 		return (-1);
12222654012fSReza Sabdar 	}
12232654012fSReza Sabdar 
12242654012fSReza Sabdar 	*tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
12252654012fSReza Sabdar 	zfs_close(zhp);
12262654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
12272654012fSReza Sabdar 
12282654012fSReza Sabdar 	return (0);
12292654012fSReza Sabdar }
12302654012fSReza Sabdar 
12312654012fSReza Sabdar 
12322654012fSReza Sabdar /*
12332654012fSReza Sabdar  * Get the ZFS volume name out of the given path
12342654012fSReza Sabdar  */
12352654012fSReza Sabdar int
get_zfsvolname(char * volname,int len,char * path)12362654012fSReza Sabdar get_zfsvolname(char *volname, int len, char *path)
12372654012fSReza Sabdar {
12382654012fSReza Sabdar 	struct stat64 stbuf;
12392654012fSReza Sabdar 	struct extmnttab ent;
12402654012fSReza Sabdar 	FILE *mntfp;
12412654012fSReza Sabdar 	int rv;
12422654012fSReza Sabdar 
12432654012fSReza Sabdar 	*volname = '\0';
12442654012fSReza Sabdar 	if (stat64(path, &stbuf) != 0) {
12452654012fSReza Sabdar 		return (-1);
12462654012fSReza Sabdar 	}
12472654012fSReza Sabdar 
12482654012fSReza Sabdar 	if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
12492654012fSReza Sabdar 		return (-1);
12502654012fSReza Sabdar 	}
12512654012fSReza Sabdar 	while ((rv = getextmntent(mntfp, &ent, 0)) == 0) {
12522654012fSReza Sabdar 		if (makedevice(ent.mnt_major, ent.mnt_minor) ==
12532654012fSReza Sabdar 		    stbuf.st_dev)
12542654012fSReza Sabdar 			break;
12552654012fSReza Sabdar 	}
12562654012fSReza Sabdar 
12572654012fSReza Sabdar 	if (rv == 0 &&
12582654012fSReza Sabdar 	    strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0)
12592654012fSReza Sabdar 		(void) strlcpy(volname, ent.mnt_special, len);
12602654012fSReza Sabdar 	else
12612654012fSReza Sabdar 		rv = -1;
12622654012fSReza Sabdar 
12632654012fSReza Sabdar 	(void) fclose(mntfp);
12642654012fSReza Sabdar 	return (rv);
12652654012fSReza Sabdar }
12662654012fSReza Sabdar 
12672654012fSReza Sabdar 
12682654012fSReza Sabdar /*
12692654012fSReza Sabdar  * Check if the volume type is snapshot volume
12702654012fSReza Sabdar  */
12712654012fSReza Sabdar boolean_t
fs_is_chkpntvol(char * path)12722654012fSReza Sabdar fs_is_chkpntvol(char *path)
12732654012fSReza Sabdar {
12742654012fSReza Sabdar 	zfs_handle_t *zhp;
1275*9adfa60dSMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
12762654012fSReza Sabdar 
12772654012fSReza Sabdar 	if (!path || !*path)
12782654012fSReza Sabdar 		return (FALSE);
12792654012fSReza Sabdar 
12802654012fSReza Sabdar 	if (get_zfsvolname(vol, sizeof (vol), path) == -1)
12812654012fSReza Sabdar 		return (FALSE);
12822654012fSReza Sabdar 
12832654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
12842654012fSReza Sabdar 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
12852654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
12862654012fSReza Sabdar 		return (FALSE);
12872654012fSReza Sabdar 	}
12882654012fSReza Sabdar 
12892654012fSReza Sabdar 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
12902654012fSReza Sabdar 		zfs_close(zhp);
12912654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
12922654012fSReza Sabdar 		return (FALSE);
12932654012fSReza Sabdar 	}
12942654012fSReza Sabdar 	zfs_close(zhp);
12952654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
12962654012fSReza Sabdar 
12972654012fSReza Sabdar 	return (TRUE);
12982654012fSReza Sabdar }
12992654012fSReza Sabdar 
13002654012fSReza Sabdar /*
13012654012fSReza Sabdar  * Check if the volume is capable of checkpoints
13022654012fSReza Sabdar  */
13032654012fSReza Sabdar boolean_t
fs_is_chkpnt_enabled(char * path)13042654012fSReza Sabdar fs_is_chkpnt_enabled(char *path)
13052654012fSReza Sabdar {
13062654012fSReza Sabdar 	zfs_handle_t *zhp;
1307*9adfa60dSMatthew Ahrens 	char vol[ZFS_MAX_DATASET_NAME_LEN];
13082654012fSReza Sabdar 
13092654012fSReza Sabdar 	if (!path || !*path)
13102654012fSReza Sabdar 		return (FALSE);
13112654012fSReza Sabdar 
13122654012fSReza Sabdar 	(void) mutex_lock(&zlib_mtx);
13132654012fSReza Sabdar 	if (get_zfsvolname(vol, sizeof (vol), path) == -1) {
13142654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
13152654012fSReza Sabdar 		return (FALSE);
13162654012fSReza Sabdar 	}
13172654012fSReza Sabdar 
13182654012fSReza Sabdar 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
13192654012fSReza Sabdar 		(void) mutex_unlock(&zlib_mtx);
13202654012fSReza Sabdar 		return (FALSE);
13212654012fSReza Sabdar 	}
13222654012fSReza Sabdar 	zfs_close(zhp);
13232654012fSReza Sabdar 	(void) mutex_unlock(&zlib_mtx);
13242654012fSReza Sabdar 
13252654012fSReza Sabdar 	return (TRUE);
13262654012fSReza Sabdar }
13272654012fSReza Sabdar 
13282654012fSReza Sabdar /*
13292654012fSReza Sabdar  * Check if the volume is read-only
13302654012fSReza Sabdar  */
13312654012fSReza Sabdar boolean_t
fs_is_rdonly(char * path)13322654012fSReza Sabdar fs_is_rdonly(char *path)
13332654012fSReza Sabdar {
13342654012fSReza Sabdar 	return (fs_is_chkpntvol(path));
13352654012fSReza Sabdar }
13362654012fSReza Sabdar 
13372654012fSReza Sabdar /*
13382654012fSReza Sabdar  * Min/max functions
13392654012fSReza Sabdar  */
13402654012fSReza Sabdar unsigned
min(unsigned a,unsigned b)1341*9adfa60dSMatthew Ahrens min(unsigned a, unsigned b)
13422654012fSReza Sabdar {
13432654012fSReza Sabdar 	return (a < b ? a : b);
13442654012fSReza Sabdar }
13452654012fSReza Sabdar 
13462654012fSReza Sabdar unsigned
max(unsigned a,unsigned b)1347*9adfa60dSMatthew Ahrens max(unsigned a, unsigned b)
13482654012fSReza Sabdar {
13492654012fSReza Sabdar 	return (a > b ? a : b);
13502654012fSReza Sabdar }
13512654012fSReza Sabdar 
13522654012fSReza Sabdar longlong_t
llmin(longlong_t a,longlong_t b)13532654012fSReza Sabdar llmin(longlong_t a, longlong_t b)
13542654012fSReza Sabdar {
13552654012fSReza Sabdar 	return (a < b ? a : b);
13562654012fSReza Sabdar }
1357