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