xref: /onnv-gate/usr/src/cmd/ndmpd/tlm/tlm_lib.c (revision 13051:60ed88a16f55)
17917SReza.Sabdar@Sun.COM /*
212186SJanice.Chang@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
37917SReza.Sabdar@Sun.COM  */
47917SReza.Sabdar@Sun.COM 
57917SReza.Sabdar@Sun.COM /*
67917SReza.Sabdar@Sun.COM  * BSD 3 Clause License
77917SReza.Sabdar@Sun.COM  *
87917SReza.Sabdar@Sun.COM  * Copyright (c) 2007, The Storage Networking Industry Association.
97917SReza.Sabdar@Sun.COM  *
107917SReza.Sabdar@Sun.COM  * Redistribution and use in source and binary forms, with or without
117917SReza.Sabdar@Sun.COM  * modification, are permitted provided that the following conditions
127917SReza.Sabdar@Sun.COM  * are met:
137917SReza.Sabdar@Sun.COM  * 	- Redistributions of source code must retain the above copyright
147917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer.
157917SReza.Sabdar@Sun.COM  *
167917SReza.Sabdar@Sun.COM  * 	- Redistributions in binary form must reproduce the above copyright
177917SReza.Sabdar@Sun.COM  *	  notice, this list of conditions and the following disclaimer in
187917SReza.Sabdar@Sun.COM  *	  the documentation and/or other materials provided with the
197917SReza.Sabdar@Sun.COM  *	  distribution.
207917SReza.Sabdar@Sun.COM  *
217917SReza.Sabdar@Sun.COM  *	- Neither the name of The Storage Networking Industry Association (SNIA)
227917SReza.Sabdar@Sun.COM  *	  nor the names of its contributors may be used to endorse or promote
237917SReza.Sabdar@Sun.COM  *	  products derived from this software without specific prior written
247917SReza.Sabdar@Sun.COM  *	  permission.
257917SReza.Sabdar@Sun.COM  *
267917SReza.Sabdar@Sun.COM  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
277917SReza.Sabdar@Sun.COM  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
287917SReza.Sabdar@Sun.COM  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
297917SReza.Sabdar@Sun.COM  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
307917SReza.Sabdar@Sun.COM  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
317917SReza.Sabdar@Sun.COM  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
327917SReza.Sabdar@Sun.COM  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
337917SReza.Sabdar@Sun.COM  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
347917SReza.Sabdar@Sun.COM  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
357917SReza.Sabdar@Sun.COM  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
367917SReza.Sabdar@Sun.COM  * POSSIBILITY OF SUCH DAMAGE.
377917SReza.Sabdar@Sun.COM  */
387917SReza.Sabdar@Sun.COM #include <sys/errno.h>
397917SReza.Sabdar@Sun.COM #include <ctype.h>
407917SReza.Sabdar@Sun.COM #include <stdlib.h>
417917SReza.Sabdar@Sun.COM #include <time.h>
427917SReza.Sabdar@Sun.COM #include <sys/types.h>
437917SReza.Sabdar@Sun.COM #include <unistd.h>
447917SReza.Sabdar@Sun.COM #include <libzfs.h>
457917SReza.Sabdar@Sun.COM #include <pthread.h>
467917SReza.Sabdar@Sun.COM #include "tlm.h"
477917SReza.Sabdar@Sun.COM #include "tlm_proto.h"
48*13051SJanice.Chang@Sun.COM #include <ndmpd_prop.h>
497917SReza.Sabdar@Sun.COM #include <sys/mtio.h>
507917SReza.Sabdar@Sun.COM #include <sys/mnttab.h>
517917SReza.Sabdar@Sun.COM #include <sys/mntent.h>
527917SReza.Sabdar@Sun.COM #include <sys/statvfs.h>
537917SReza.Sabdar@Sun.COM #include <sys/scsi/impl/uscsi.h>
547917SReza.Sabdar@Sun.COM #include <sys/scsi/scsi.h>
557917SReza.Sabdar@Sun.COM #include <sys/mtio.h>
567917SReza.Sabdar@Sun.COM #include <thread.h>
577917SReza.Sabdar@Sun.COM #include <synch.h>
587917SReza.Sabdar@Sun.COM #include <sys/mutex.h>
597917SReza.Sabdar@Sun.COM #include <sys/sysmacros.h>
607917SReza.Sabdar@Sun.COM #include <sys/mkdev.h>
617917SReza.Sabdar@Sun.COM 
627917SReza.Sabdar@Sun.COM /*
637917SReza.Sabdar@Sun.COM  * Tar archiving ops vector
647917SReza.Sabdar@Sun.COM  */
657917SReza.Sabdar@Sun.COM tm_ops_t tm_tar_ops = {
667917SReza.Sabdar@Sun.COM 	"tar",
677917SReza.Sabdar@Sun.COM 	tar_putfile,
687917SReza.Sabdar@Sun.COM 	tar_putdir,
697917SReza.Sabdar@Sun.COM 	NULL,
707917SReza.Sabdar@Sun.COM 	tar_getfile,
717917SReza.Sabdar@Sun.COM 	tar_getdir,
727917SReza.Sabdar@Sun.COM 	NULL
737917SReza.Sabdar@Sun.COM };
747917SReza.Sabdar@Sun.COM 
757917SReza.Sabdar@Sun.COM extern	libzfs_handle_t *zlibh;
767917SReza.Sabdar@Sun.COM extern	mutex_t zlib_mtx;
777917SReza.Sabdar@Sun.COM 
787917SReza.Sabdar@Sun.COM /*
797917SReza.Sabdar@Sun.COM  * get the next tape buffer from the drive's pool of buffers
807917SReza.Sabdar@Sun.COM  */
817917SReza.Sabdar@Sun.COM /*ARGSUSED*/
827917SReza.Sabdar@Sun.COM char *
tlm_get_write_buffer(long want,long * actual_size,tlm_buffers_t * buffers,int zero)837917SReza.Sabdar@Sun.COM tlm_get_write_buffer(long want, long *actual_size,
847917SReza.Sabdar@Sun.COM     tlm_buffers_t *buffers, int zero)
857917SReza.Sabdar@Sun.COM {
867917SReza.Sabdar@Sun.COM 	int	buf = buffers->tbs_buffer_in;
877917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buffer = &buffers->tbs_buffer[buf];
887917SReza.Sabdar@Sun.COM 	int	align_size = RECORDSIZE - 1;
897917SReza.Sabdar@Sun.COM 	char	*rec;
907917SReza.Sabdar@Sun.COM 
917917SReza.Sabdar@Sun.COM 	/*
927917SReza.Sabdar@Sun.COM 	 * make sure the allocation is in chunks of 512 bytes
937917SReza.Sabdar@Sun.COM 	 */
947917SReza.Sabdar@Sun.COM 	want += align_size;
957917SReza.Sabdar@Sun.COM 	want &= ~align_size;
967917SReza.Sabdar@Sun.COM 
977917SReza.Sabdar@Sun.COM 	*actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
987917SReza.Sabdar@Sun.COM 	if (*actual_size <= 0) {
997917SReza.Sabdar@Sun.COM 		/*
1007917SReza.Sabdar@Sun.COM 		 * no room, send this one
1017917SReza.Sabdar@Sun.COM 		 * and wait for a free one
1027917SReza.Sabdar@Sun.COM 		 */
1037917SReza.Sabdar@Sun.COM 		if (!buffer->tb_full) {
1047917SReza.Sabdar@Sun.COM 			/*
1057917SReza.Sabdar@Sun.COM 			 * we are now ready to send a full buffer
1067917SReza.Sabdar@Sun.COM 			 * instead of trying to get a new buffer
1077917SReza.Sabdar@Sun.COM 			 *
1087917SReza.Sabdar@Sun.COM 			 * do not send if we failed to get a buffer
1097917SReza.Sabdar@Sun.COM 			 * on the previous call
1107917SReza.Sabdar@Sun.COM 			 */
1117917SReza.Sabdar@Sun.COM 			buffer->tb_full = TRUE;
1127917SReza.Sabdar@Sun.COM 
1137917SReza.Sabdar@Sun.COM 			/*
1147917SReza.Sabdar@Sun.COM 			 * tell the writer that a buffer is available
1157917SReza.Sabdar@Sun.COM 			 */
1167917SReza.Sabdar@Sun.COM 			tlm_buffer_release_in_buf(buffers);
1177917SReza.Sabdar@Sun.COM 
1187917SReza.Sabdar@Sun.COM 			buffer = tlm_buffer_advance_in_idx(buffers);
1197917SReza.Sabdar@Sun.COM 		}
1207917SReza.Sabdar@Sun.COM 
1217917SReza.Sabdar@Sun.COM 		buffer = tlm_buffer_in_buf(buffers, NULL);
1227917SReza.Sabdar@Sun.COM 
1237917SReza.Sabdar@Sun.COM 		if (buffer->tb_full) {
1247917SReza.Sabdar@Sun.COM 			/*
1257917SReza.Sabdar@Sun.COM 			 * wait for the writer to free up a buffer
1267917SReza.Sabdar@Sun.COM 			 */
1277917SReza.Sabdar@Sun.COM 			tlm_buffer_out_buf_timed_wait(buffers, 500);
1287917SReza.Sabdar@Sun.COM 		}
1297917SReza.Sabdar@Sun.COM 
1307917SReza.Sabdar@Sun.COM 		buffer = tlm_buffer_in_buf(buffers, NULL);
1317917SReza.Sabdar@Sun.COM 		if (buffer->tb_full) {
1327917SReza.Sabdar@Sun.COM 			/*
1337917SReza.Sabdar@Sun.COM 			 * the next buffer is still full
1347917SReza.Sabdar@Sun.COM 			 * of data from previous activity
1357917SReza.Sabdar@Sun.COM 			 *
1367917SReza.Sabdar@Sun.COM 			 * nothing has changed.
1377917SReza.Sabdar@Sun.COM 			 */
1387917SReza.Sabdar@Sun.COM 			return (0);
1397917SReza.Sabdar@Sun.COM 		}
1407917SReza.Sabdar@Sun.COM 
1417917SReza.Sabdar@Sun.COM 		buffer->tb_buffer_spot = 0;
1427917SReza.Sabdar@Sun.COM 		*actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
1437917SReza.Sabdar@Sun.COM 	}
1447917SReza.Sabdar@Sun.COM 
1457917SReza.Sabdar@Sun.COM 	*actual_size = min(want, *actual_size);
1467917SReza.Sabdar@Sun.COM 	rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot];
1477917SReza.Sabdar@Sun.COM 	buffer->tb_buffer_spot += *actual_size;
1487917SReza.Sabdar@Sun.COM 	buffers->tbs_offset += *actual_size;
1497917SReza.Sabdar@Sun.COM 	if (zero) {
1507917SReza.Sabdar@Sun.COM 		(void) memset(rec, 0, *actual_size);
1517917SReza.Sabdar@Sun.COM 	}
1527917SReza.Sabdar@Sun.COM 	return (rec);
1537917SReza.Sabdar@Sun.COM }
1547917SReza.Sabdar@Sun.COM 
1557917SReza.Sabdar@Sun.COM /*
1567917SReza.Sabdar@Sun.COM  * get a read record from the tape buffer,
1577917SReza.Sabdar@Sun.COM  * and read a tape block if necessary
1587917SReza.Sabdar@Sun.COM  */
1597917SReza.Sabdar@Sun.COM /*ARGSUSED*/
1607917SReza.Sabdar@Sun.COM char *
tlm_get_read_buffer(int want,int * error,tlm_buffers_t * buffers,int * actual_size)1617917SReza.Sabdar@Sun.COM tlm_get_read_buffer(int want, int *error,
1627917SReza.Sabdar@Sun.COM     tlm_buffers_t *buffers, int *actual_size)
1637917SReza.Sabdar@Sun.COM {
1647917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buffer;
1657917SReza.Sabdar@Sun.COM 	int	align_size = RECORDSIZE - 1;
1667917SReza.Sabdar@Sun.COM 	int	buf;
1677917SReza.Sabdar@Sun.COM 	int	current_size;
1687917SReza.Sabdar@Sun.COM 	char	*rec;
1697917SReza.Sabdar@Sun.COM 
1707917SReza.Sabdar@Sun.COM 	buf = buffers->tbs_buffer_out;
1717917SReza.Sabdar@Sun.COM 	buffer = &buffers->tbs_buffer[buf];
1727917SReza.Sabdar@Sun.COM 
1737917SReza.Sabdar@Sun.COM 	/*
1747917SReza.Sabdar@Sun.COM 	 * make sure the allocation is in chunks of 512 bytes
1757917SReza.Sabdar@Sun.COM 	 */
1767917SReza.Sabdar@Sun.COM 	want += align_size;
1777917SReza.Sabdar@Sun.COM 	want &= ~align_size;
1787917SReza.Sabdar@Sun.COM 
1797917SReza.Sabdar@Sun.COM 	current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
1807917SReza.Sabdar@Sun.COM 	if (buffer->tb_full && current_size <= 0) {
1817917SReza.Sabdar@Sun.COM 		/*
1827917SReza.Sabdar@Sun.COM 		 * no more data, release this
1837917SReza.Sabdar@Sun.COM 		 * one and go get another
1847917SReza.Sabdar@Sun.COM 		 */
1857917SReza.Sabdar@Sun.COM 
1867917SReza.Sabdar@Sun.COM 		/*
1877917SReza.Sabdar@Sun.COM 		 * tell the reader that a buffer is available
1887917SReza.Sabdar@Sun.COM 		 */
1897917SReza.Sabdar@Sun.COM 		buffer->tb_full = FALSE;
1907917SReza.Sabdar@Sun.COM 		tlm_buffer_release_out_buf(buffers);
1917917SReza.Sabdar@Sun.COM 
1927917SReza.Sabdar@Sun.COM 		buffer = tlm_buffer_advance_out_idx(buffers);
1937917SReza.Sabdar@Sun.COM 		current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
1947917SReza.Sabdar@Sun.COM 	}
1957917SReza.Sabdar@Sun.COM 
1967917SReza.Sabdar@Sun.COM 	if (!buffer->tb_full) {
1977917SReza.Sabdar@Sun.COM 		/*
1987917SReza.Sabdar@Sun.COM 		 * next buffer is not full yet.
1997917SReza.Sabdar@Sun.COM 		 * wait for the reader.
2007917SReza.Sabdar@Sun.COM 		 */
2017917SReza.Sabdar@Sun.COM 		tlm_buffer_in_buf_timed_wait(buffers, 500);
2027917SReza.Sabdar@Sun.COM 
2037917SReza.Sabdar@Sun.COM 		buffer = tlm_buffer_out_buf(buffers, NULL);
2047917SReza.Sabdar@Sun.COM 		if (!buffer->tb_full) {
2057917SReza.Sabdar@Sun.COM 			/*
2067917SReza.Sabdar@Sun.COM 			 * we do not have anything from the tape yet
2077917SReza.Sabdar@Sun.COM 			 */
2087917SReza.Sabdar@Sun.COM 			return (0);
2097917SReza.Sabdar@Sun.COM 		}
2107917SReza.Sabdar@Sun.COM 
2117917SReza.Sabdar@Sun.COM 		current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
2127917SReza.Sabdar@Sun.COM 	}
2137917SReza.Sabdar@Sun.COM 
2147917SReza.Sabdar@Sun.COM 	/* Make sure we got something */
2157917SReza.Sabdar@Sun.COM 	if (current_size <= 0)
2167917SReza.Sabdar@Sun.COM 		return (NULL);
2177917SReza.Sabdar@Sun.COM 
2187917SReza.Sabdar@Sun.COM 	current_size = min(want, current_size);
2197917SReza.Sabdar@Sun.COM 	rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot];
2207917SReza.Sabdar@Sun.COM 	buffer->tb_buffer_spot += current_size;
2217917SReza.Sabdar@Sun.COM 	*actual_size = current_size;
2227917SReza.Sabdar@Sun.COM 
2237917SReza.Sabdar@Sun.COM 	/*
2247917SReza.Sabdar@Sun.COM 	 * the error flag is only sent back one time,
2257917SReza.Sabdar@Sun.COM 	 * since the flag refers to a previous read
2267917SReza.Sabdar@Sun.COM 	 * attempt, not the data in this buffer.
2277917SReza.Sabdar@Sun.COM 	 */
2287917SReza.Sabdar@Sun.COM 	*error = buffer->tb_errno;
2297917SReza.Sabdar@Sun.COM 
2307917SReza.Sabdar@Sun.COM 	return (rec);
2317917SReza.Sabdar@Sun.COM }
2327917SReza.Sabdar@Sun.COM 
2337917SReza.Sabdar@Sun.COM 
2347917SReza.Sabdar@Sun.COM /*
2357917SReza.Sabdar@Sun.COM  * unread a previously read buffer back to the tape buffer
2367917SReza.Sabdar@Sun.COM  */
2377917SReza.Sabdar@Sun.COM void
tlm_unget_read_buffer(tlm_buffers_t * buffers,int size)2387917SReza.Sabdar@Sun.COM tlm_unget_read_buffer(tlm_buffers_t *buffers, int size)
2397917SReza.Sabdar@Sun.COM {
2407917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buffer;
2417917SReza.Sabdar@Sun.COM 	int	align_size = RECORDSIZE - 1;
2427917SReza.Sabdar@Sun.COM 	int	buf;
2437917SReza.Sabdar@Sun.COM 	int	current_size;
2447917SReza.Sabdar@Sun.COM 
2457917SReza.Sabdar@Sun.COM 	buf = buffers->tbs_buffer_out;
2467917SReza.Sabdar@Sun.COM 	buffer = &buffers->tbs_buffer[buf];
2477917SReza.Sabdar@Sun.COM 
2487917SReza.Sabdar@Sun.COM 	/*
2497917SReza.Sabdar@Sun.COM 	 * make sure the allocation is in chunks of 512 bytes
2507917SReza.Sabdar@Sun.COM 	 */
2517917SReza.Sabdar@Sun.COM 	size += align_size;
2527917SReza.Sabdar@Sun.COM 	size &= ~align_size;
2537917SReza.Sabdar@Sun.COM 
2547917SReza.Sabdar@Sun.COM 	current_size = min(size, buffer->tb_buffer_spot);
2557917SReza.Sabdar@Sun.COM 	buffer->tb_buffer_spot -= current_size;
2567917SReza.Sabdar@Sun.COM }
2577917SReza.Sabdar@Sun.COM 
2587917SReza.Sabdar@Sun.COM 
2597917SReza.Sabdar@Sun.COM /*
2607917SReza.Sabdar@Sun.COM  * unwrite a previously written buffer
2617917SReza.Sabdar@Sun.COM  */
2627917SReza.Sabdar@Sun.COM void
tlm_unget_write_buffer(tlm_buffers_t * buffers,int size)2637917SReza.Sabdar@Sun.COM tlm_unget_write_buffer(tlm_buffers_t *buffers, int size)
2647917SReza.Sabdar@Sun.COM {
2657917SReza.Sabdar@Sun.COM 	tlm_buffer_t *buffer;
2667917SReza.Sabdar@Sun.COM 	int	align_size = RECORDSIZE - 1;
2677917SReza.Sabdar@Sun.COM 	int	buf;
2687917SReza.Sabdar@Sun.COM 	int	current_size;
2697917SReza.Sabdar@Sun.COM 
2707917SReza.Sabdar@Sun.COM 	buf = buffers->tbs_buffer_in;
2717917SReza.Sabdar@Sun.COM 	buffer = &buffers->tbs_buffer[buf];
2727917SReza.Sabdar@Sun.COM 
2737917SReza.Sabdar@Sun.COM 	/*
2747917SReza.Sabdar@Sun.COM 	 * make sure the allocation is in chunks of 512 bytes
2757917SReza.Sabdar@Sun.COM 	 */
2767917SReza.Sabdar@Sun.COM 	size += align_size;
2777917SReza.Sabdar@Sun.COM 	size &= ~align_size;
2787917SReza.Sabdar@Sun.COM 
2797917SReza.Sabdar@Sun.COM 	current_size = min(size, buffer->tb_buffer_spot);
2807917SReza.Sabdar@Sun.COM 	buffer->tb_buffer_spot -= current_size;
2817917SReza.Sabdar@Sun.COM }
2827917SReza.Sabdar@Sun.COM 
2837917SReza.Sabdar@Sun.COM 
2847917SReza.Sabdar@Sun.COM /*
2857917SReza.Sabdar@Sun.COM  * build a checksum for a TAR header record
2867917SReza.Sabdar@Sun.COM  */
2877917SReza.Sabdar@Sun.COM void
tlm_build_header_checksum(tlm_tar_hdr_t * r)2887917SReza.Sabdar@Sun.COM tlm_build_header_checksum(tlm_tar_hdr_t *r)
2897917SReza.Sabdar@Sun.COM {
2907917SReza.Sabdar@Sun.COM 	int	i;
2917917SReza.Sabdar@Sun.COM 	int	sum = 0;
2927917SReza.Sabdar@Sun.COM 	char *c = (char *)r;
2937917SReza.Sabdar@Sun.COM 
2947917SReza.Sabdar@Sun.COM 	(void) memcpy(r->th_chksum, CHKBLANKS, strlen(CHKBLANKS));
2957917SReza.Sabdar@Sun.COM 	for (i = 0; i < RECORDSIZE; i++) {
2967917SReza.Sabdar@Sun.COM 		sum += c[i] & 0xFF;
2977917SReza.Sabdar@Sun.COM 	}
2987917SReza.Sabdar@Sun.COM 	(void) snprintf(r->th_chksum, sizeof (r->th_chksum), "%6o", sum);
2997917SReza.Sabdar@Sun.COM }
3007917SReza.Sabdar@Sun.COM 
3017917SReza.Sabdar@Sun.COM /*
3027917SReza.Sabdar@Sun.COM  * verify the tar header checksum
3037917SReza.Sabdar@Sun.COM  */
3047917SReza.Sabdar@Sun.COM int
tlm_vfy_tar_checksum(tlm_tar_hdr_t * tar_hdr)3057917SReza.Sabdar@Sun.COM tlm_vfy_tar_checksum(tlm_tar_hdr_t *tar_hdr)
3067917SReza.Sabdar@Sun.COM {
3077917SReza.Sabdar@Sun.COM 	int	chksum = oct_atoi(tar_hdr->th_chksum);
3087917SReza.Sabdar@Sun.COM 	uchar_t	*p = (uchar_t *)tar_hdr;
3097917SReza.Sabdar@Sun.COM 	int	sum = 0;	/* initial value of checksum */
3107917SReza.Sabdar@Sun.COM 	int	i;		/* loop counter */
3117917SReza.Sabdar@Sun.COM 
3127917SReza.Sabdar@Sun.COM 	/*
3137917SReza.Sabdar@Sun.COM 	 * compute the checksum
3147917SReza.Sabdar@Sun.COM 	 */
3157917SReza.Sabdar@Sun.COM 	for (i = 0; i < RECORDSIZE; i++) {
3167917SReza.Sabdar@Sun.COM 		sum += p[i] & 0xFF;
3177917SReza.Sabdar@Sun.COM 	}
3187917SReza.Sabdar@Sun.COM 
3197917SReza.Sabdar@Sun.COM 	if (sum == 0) {
3207917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
3217917SReza.Sabdar@Sun.COM 		    "should be %d, is 0", chksum);
3227917SReza.Sabdar@Sun.COM 		/* a zero record ==> end of tar file */
3237917SReza.Sabdar@Sun.COM 		return (0);
3247917SReza.Sabdar@Sun.COM 	}
3257917SReza.Sabdar@Sun.COM 
3267917SReza.Sabdar@Sun.COM 	/*
3277917SReza.Sabdar@Sun.COM 	 * subtract out the label's checksum values
3287917SReza.Sabdar@Sun.COM 	 * this lets us undo the old checksum "in-
3297917SReza.Sabdar@Sun.COM 	 * place", no need to swap blanks in and out
3307917SReza.Sabdar@Sun.COM 	 */
3317917SReza.Sabdar@Sun.COM 	for (i = 0; i < 8; i++) {
3327917SReza.Sabdar@Sun.COM 		sum -= 0xFF & tar_hdr->th_chksum[i];
3337917SReza.Sabdar@Sun.COM 	}
3347917SReza.Sabdar@Sun.COM 
3357917SReza.Sabdar@Sun.COM 	/*
3367917SReza.Sabdar@Sun.COM 	 * replace the old checksum field with blanks
3377917SReza.Sabdar@Sun.COM 	 */
3387917SReza.Sabdar@Sun.COM 	sum += ' ' * 8;
3397917SReza.Sabdar@Sun.COM 
3407917SReza.Sabdar@Sun.COM 	if (sum != chksum)
3417917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
3427917SReza.Sabdar@Sun.COM 		    "should be %d, is %d", chksum, sum);
3437917SReza.Sabdar@Sun.COM 
3447917SReza.Sabdar@Sun.COM 	return ((sum == chksum) ? 1 : -1);
3457917SReza.Sabdar@Sun.COM }
3467917SReza.Sabdar@Sun.COM 
3477917SReza.Sabdar@Sun.COM /*
3487917SReza.Sabdar@Sun.COM  * get internal scsi_sasd entry for this tape drive
3497917SReza.Sabdar@Sun.COM  */
3507917SReza.Sabdar@Sun.COM int
tlm_get_scsi_sasd_entry(int lib,int drv)3517917SReza.Sabdar@Sun.COM tlm_get_scsi_sasd_entry(int lib, int drv)
3527917SReza.Sabdar@Sun.COM {
3537917SReza.Sabdar@Sun.COM 	int entry;
3547917SReza.Sabdar@Sun.COM 	int i, n;
3557917SReza.Sabdar@Sun.COM 	scsi_link_t *sl;
3567917SReza.Sabdar@Sun.COM 	tlm_drive_t *dp;
3577917SReza.Sabdar@Sun.COM 
3587917SReza.Sabdar@Sun.COM 	entry = -1;
3597917SReza.Sabdar@Sun.COM 	dp = tlm_drive(lib, drv);
3607917SReza.Sabdar@Sun.COM 	if (!dp) {
3617917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "NULL dp for (%d.%d)", lib, drv);
3627917SReza.Sabdar@Sun.COM 	} else if (!dp->td_slink) {
3637917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink for (%d.%d)", lib, drv);
3647917SReza.Sabdar@Sun.COM 	} else if (!dp->td_slink->sl_sa) {
3657917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink->sl_sa for (%d.%d)",
3667917SReza.Sabdar@Sun.COM 		    lib, drv);
3677917SReza.Sabdar@Sun.COM 	} else {
3687917SReza.Sabdar@Sun.COM 		/* search through the SASD table */
3697917SReza.Sabdar@Sun.COM 		n = sasd_dev_count();
3707917SReza.Sabdar@Sun.COM 		for (i = 0; i < n; i++) {
3717917SReza.Sabdar@Sun.COM 			sl = sasd_dev_slink(i);
3727917SReza.Sabdar@Sun.COM 			if (!sl)
3737917SReza.Sabdar@Sun.COM 				continue;
3747917SReza.Sabdar@Sun.COM 
3757917SReza.Sabdar@Sun.COM 			if (dp->td_slink->sl_sa == sl->sl_sa &&
3767917SReza.Sabdar@Sun.COM 			    dp->td_scsi_id == sl->sl_sid &&
3777917SReza.Sabdar@Sun.COM 			    dp->td_lun == sl->sl_lun) {
3787917SReza.Sabdar@Sun.COM 				/* all 3 variables match */
3797917SReza.Sabdar@Sun.COM 				entry = i;
3807917SReza.Sabdar@Sun.COM 				break;
3817917SReza.Sabdar@Sun.COM 			}
3827917SReza.Sabdar@Sun.COM 		}
3837917SReza.Sabdar@Sun.COM 	}
3847917SReza.Sabdar@Sun.COM 
3857917SReza.Sabdar@Sun.COM 	return (entry);
3867917SReza.Sabdar@Sun.COM }
3877917SReza.Sabdar@Sun.COM 
3887917SReza.Sabdar@Sun.COM /*
3897917SReza.Sabdar@Sun.COM  * get the OS device name for this tape
3907917SReza.Sabdar@Sun.COM  */
3917917SReza.Sabdar@Sun.COM char *
tlm_get_tape_name(int lib,int drv)3927917SReza.Sabdar@Sun.COM tlm_get_tape_name(int lib, int drv)
3937917SReza.Sabdar@Sun.COM {
3947917SReza.Sabdar@Sun.COM 	int entry;
3957917SReza.Sabdar@Sun.COM 
3967917SReza.Sabdar@Sun.COM 	entry = tlm_get_scsi_sasd_entry(lib, drv);
3977917SReza.Sabdar@Sun.COM 	if (entry >= 0) {
3987917SReza.Sabdar@Sun.COM 		sasd_drive_t *sd;
3997917SReza.Sabdar@Sun.COM 
4007917SReza.Sabdar@Sun.COM 		if ((sd = sasd_drive(entry)) != 0)
4017917SReza.Sabdar@Sun.COM 			return (sd->sd_name);
4027917SReza.Sabdar@Sun.COM 	}
4037917SReza.Sabdar@Sun.COM 
4047917SReza.Sabdar@Sun.COM 	return ("");
4057917SReza.Sabdar@Sun.COM }
4067917SReza.Sabdar@Sun.COM 
4077917SReza.Sabdar@Sun.COM /*
4087917SReza.Sabdar@Sun.COM  * create the IPC area between the reader and writer
4097917SReza.Sabdar@Sun.COM  */
4107917SReza.Sabdar@Sun.COM tlm_cmd_t *
tlm_create_reader_writer_ipc(boolean_t write,long data_transfer_size)4117917SReza.Sabdar@Sun.COM tlm_create_reader_writer_ipc(boolean_t write, long data_transfer_size)
4127917SReza.Sabdar@Sun.COM {
4137917SReza.Sabdar@Sun.COM 	tlm_cmd_t *cmd;
4147917SReza.Sabdar@Sun.COM 
4157917SReza.Sabdar@Sun.COM 	cmd = ndmp_malloc(sizeof (tlm_cmd_t));
4167917SReza.Sabdar@Sun.COM 	if (cmd == NULL)
4177917SReza.Sabdar@Sun.COM 		return (NULL);
4187917SReza.Sabdar@Sun.COM 
4197917SReza.Sabdar@Sun.COM 	cmd->tc_reader = TLM_BACKUP_RUN;
4207917SReza.Sabdar@Sun.COM 	cmd->tc_writer = TLM_BACKUP_RUN;
4217917SReza.Sabdar@Sun.COM 	cmd->tc_ref = 1;
4227917SReza.Sabdar@Sun.COM 
4237917SReza.Sabdar@Sun.COM 	cmd->tc_buffers = tlm_allocate_buffers(write, data_transfer_size);
4247917SReza.Sabdar@Sun.COM 	if (cmd->tc_buffers == NULL) {
4257917SReza.Sabdar@Sun.COM 		free(cmd);
4267917SReza.Sabdar@Sun.COM 		return (NULL);
4277917SReza.Sabdar@Sun.COM 	}
4287917SReza.Sabdar@Sun.COM 
4297917SReza.Sabdar@Sun.COM 	(void) mutex_init(&cmd->tc_mtx, 0, NULL);
4307917SReza.Sabdar@Sun.COM 	(void) cond_init(&cmd->tc_cv, 0, NULL);
4317917SReza.Sabdar@Sun.COM 
4327917SReza.Sabdar@Sun.COM 	return (cmd);
4337917SReza.Sabdar@Sun.COM }
4347917SReza.Sabdar@Sun.COM 
4357917SReza.Sabdar@Sun.COM /*
4367917SReza.Sabdar@Sun.COM  * release(destroy) the IPC between the reader and writer
4377917SReza.Sabdar@Sun.COM  */
4387917SReza.Sabdar@Sun.COM void
tlm_release_reader_writer_ipc(tlm_cmd_t * cmd)4397917SReza.Sabdar@Sun.COM tlm_release_reader_writer_ipc(tlm_cmd_t *cmd)
4407917SReza.Sabdar@Sun.COM {
4417917SReza.Sabdar@Sun.COM 	if (--cmd->tc_ref <= 0) {
4427917SReza.Sabdar@Sun.COM 		(void) mutex_lock(&cmd->tc_mtx);
4437917SReza.Sabdar@Sun.COM 		tlm_release_buffers(cmd->tc_buffers);
4447917SReza.Sabdar@Sun.COM 		(void) cond_destroy(&cmd->tc_cv);
4457917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&cmd->tc_mtx);
4467917SReza.Sabdar@Sun.COM 		(void) mutex_destroy(&cmd->tc_mtx);
4477917SReza.Sabdar@Sun.COM 		free(cmd);
4487917SReza.Sabdar@Sun.COM 	}
4497917SReza.Sabdar@Sun.COM }
4507917SReza.Sabdar@Sun.COM 
4517917SReza.Sabdar@Sun.COM 
4527917SReza.Sabdar@Sun.COM /*
4537917SReza.Sabdar@Sun.COM  * NDMP support begins here.
4547917SReza.Sabdar@Sun.COM  */
4557917SReza.Sabdar@Sun.COM 
4567917SReza.Sabdar@Sun.COM /*
4577917SReza.Sabdar@Sun.COM  * Initialize the file history callback functions
4587917SReza.Sabdar@Sun.COM  */
4597917SReza.Sabdar@Sun.COM 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)4607917SReza.Sabdar@Sun.COM lbrlog_callbacks_init(void *cookie, path_hist_func_t log_pname_func,
4617917SReza.Sabdar@Sun.COM     dir_hist_func_t log_dir_func, node_hist_func_t log_node_func)
4627917SReza.Sabdar@Sun.COM {
4637917SReza.Sabdar@Sun.COM 	lbr_fhlog_call_backs_t *p;
4647917SReza.Sabdar@Sun.COM 
4657917SReza.Sabdar@Sun.COM 	p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t));
4667917SReza.Sabdar@Sun.COM 	if (p == NULL)
4677917SReza.Sabdar@Sun.COM 		return (NULL);
4687917SReza.Sabdar@Sun.COM 
4697917SReza.Sabdar@Sun.COM 	p->fh_cookie = cookie;
4707917SReza.Sabdar@Sun.COM 	p->fh_logpname = (func_t)log_pname_func;
4717917SReza.Sabdar@Sun.COM 	p->fh_log_dir = (func_t)log_dir_func;
4727917SReza.Sabdar@Sun.COM 	p->fh_log_node = (func_t)log_node_func;
4737917SReza.Sabdar@Sun.COM 	return (p);
4747917SReza.Sabdar@Sun.COM }
4757917SReza.Sabdar@Sun.COM 
4767917SReza.Sabdar@Sun.COM /*
4777917SReza.Sabdar@Sun.COM  * Cleanup the callbacks
4787917SReza.Sabdar@Sun.COM  */
4797917SReza.Sabdar@Sun.COM void
lbrlog_callbacks_done(lbr_fhlog_call_backs_t * p)4807917SReza.Sabdar@Sun.COM lbrlog_callbacks_done(lbr_fhlog_call_backs_t *p)
4817917SReza.Sabdar@Sun.COM {
4827917SReza.Sabdar@Sun.COM 	if (p != NULL)
4837917SReza.Sabdar@Sun.COM 		(void) free((char *)p);
4847917SReza.Sabdar@Sun.COM }
4857917SReza.Sabdar@Sun.COM 
4867917SReza.Sabdar@Sun.COM /*
4877917SReza.Sabdar@Sun.COM  * Call back for file history directory info
4887917SReza.Sabdar@Sun.COM  */
4897917SReza.Sabdar@Sun.COM int
tlm_log_fhdir(tlm_job_stats_t * job_stats,char * dir,struct stat64 * stp,fs_fhandle_t * fhp)4907917SReza.Sabdar@Sun.COM tlm_log_fhdir(tlm_job_stats_t *job_stats, char *dir, struct stat64 *stp,
4917917SReza.Sabdar@Sun.COM     fs_fhandle_t *fhp)
4927917SReza.Sabdar@Sun.COM {
4937917SReza.Sabdar@Sun.COM 	int rv;
4947917SReza.Sabdar@Sun.COM 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
4957917SReza.Sabdar@Sun.COM 
4967917SReza.Sabdar@Sun.COM 	rv = 0;
4977917SReza.Sabdar@Sun.COM 	if (job_stats == NULL) {
4987917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhdir: jstat is NULL");
4997917SReza.Sabdar@Sun.COM 	} else if (dir == NULL) {
5007917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhdir: dir is NULL");
5017917SReza.Sabdar@Sun.COM 	} else if (stp == NULL) {
5027917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhdir: stp is NULL");
5037917SReza.Sabdar@Sun.COM 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
5047917SReza.Sabdar@Sun.COM 	    == NULL) {
5057917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhdir: cbp is NULL");
5067917SReza.Sabdar@Sun.COM 	} else if (cbp->fh_log_dir == NULL) {
5077917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhdir: callback is NULL");
5087917SReza.Sabdar@Sun.COM 	} else
5097917SReza.Sabdar@Sun.COM 		rv = (*cbp->fh_log_dir)(cbp, dir, stp, fhp);
5107917SReza.Sabdar@Sun.COM 
5117917SReza.Sabdar@Sun.COM 	return (rv);
5127917SReza.Sabdar@Sun.COM }
5137917SReza.Sabdar@Sun.COM 
5147917SReza.Sabdar@Sun.COM /*
5157917SReza.Sabdar@Sun.COM  * Call back for file history node info
5167917SReza.Sabdar@Sun.COM  */
5177917SReza.Sabdar@Sun.COM int
tlm_log_fhnode(tlm_job_stats_t * job_stats,char * dir,char * file,struct stat64 * stp,u_longlong_t off)5187917SReza.Sabdar@Sun.COM tlm_log_fhnode(tlm_job_stats_t *job_stats, char *dir, char *file,
5197917SReza.Sabdar@Sun.COM     struct stat64 *stp, u_longlong_t off)
5207917SReza.Sabdar@Sun.COM {
5217917SReza.Sabdar@Sun.COM 	int rv;
5227917SReza.Sabdar@Sun.COM 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
5237917SReza.Sabdar@Sun.COM 
5247917SReza.Sabdar@Sun.COM 	rv = 0;
5257917SReza.Sabdar@Sun.COM 	if (job_stats == NULL) {
5267917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhnode: jstat is NULL");
5277917SReza.Sabdar@Sun.COM 	} else if (dir == NULL) {
5287917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhnode: dir is NULL");
5297917SReza.Sabdar@Sun.COM 	} else if (file == NULL) {
5307917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhnode: file is NULL");
5317917SReza.Sabdar@Sun.COM 	} else if (stp == NULL) {
5327917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhnode: stp is NULL");
5337917SReza.Sabdar@Sun.COM 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
5347917SReza.Sabdar@Sun.COM 	    == NULL) {
5357917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhnode: cbp is NULL");
5367917SReza.Sabdar@Sun.COM 	} else if (cbp->fh_log_node == NULL) {
5377917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhnode: callback is NULL");
5387917SReza.Sabdar@Sun.COM 	} else
5397917SReza.Sabdar@Sun.COM 		rv = (*cbp->fh_log_node)(cbp, dir, file, stp, off);
5407917SReza.Sabdar@Sun.COM 
5417917SReza.Sabdar@Sun.COM 	return (rv);
5427917SReza.Sabdar@Sun.COM }
5437917SReza.Sabdar@Sun.COM 
5447917SReza.Sabdar@Sun.COM /*
5457917SReza.Sabdar@Sun.COM  * Call back for file history path info
5467917SReza.Sabdar@Sun.COM  */
5477917SReza.Sabdar@Sun.COM int
tlm_log_fhpath_name(tlm_job_stats_t * job_stats,char * pathname,struct stat64 * stp,u_longlong_t off)5487917SReza.Sabdar@Sun.COM tlm_log_fhpath_name(tlm_job_stats_t *job_stats, char *pathname,
5497917SReza.Sabdar@Sun.COM     struct stat64 *stp, u_longlong_t off)
5507917SReza.Sabdar@Sun.COM {
5517917SReza.Sabdar@Sun.COM 	int rv;
5527917SReza.Sabdar@Sun.COM 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
5537917SReza.Sabdar@Sun.COM 
5547917SReza.Sabdar@Sun.COM 	rv = 0;
5557917SReza.Sabdar@Sun.COM 	if (!job_stats) {
5567917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: jstat is NULL");
5577917SReza.Sabdar@Sun.COM 	} else if (!pathname) {
5587917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: pathname is NULL");
5597917SReza.Sabdar@Sun.COM 	} else if (!stp) {
5607917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: stp is NULL");
5617917SReza.Sabdar@Sun.COM 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
5627917SReza.Sabdar@Sun.COM 	    == 0) {
5637917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: cbp is NULL");
5647917SReza.Sabdar@Sun.COM 	} else if (!cbp->fh_logpname) {
5657917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: callback is NULL");
5667917SReza.Sabdar@Sun.COM 	} else
5677917SReza.Sabdar@Sun.COM 		rv = (*cbp->fh_logpname)(cbp, pathname, stp, off);
5687917SReza.Sabdar@Sun.COM 
5697917SReza.Sabdar@Sun.COM 	return (rv);
5707917SReza.Sabdar@Sun.COM }
5717917SReza.Sabdar@Sun.COM 
5727917SReza.Sabdar@Sun.COM 
5737917SReza.Sabdar@Sun.COM /*
5747917SReza.Sabdar@Sun.COM  * Log call back to report the entry recovery
5757917SReza.Sabdar@Sun.COM  */
5767917SReza.Sabdar@Sun.COM int
tlm_entry_restored(tlm_job_stats_t * job_stats,char * name,int pos)5777917SReza.Sabdar@Sun.COM tlm_entry_restored(tlm_job_stats_t *job_stats, char *name, int pos)
5787917SReza.Sabdar@Sun.COM {
5797917SReza.Sabdar@Sun.COM 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
5807917SReza.Sabdar@Sun.COM 
5817917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d", name, pos);
5827917SReza.Sabdar@Sun.COM 
5837917SReza.Sabdar@Sun.COM 	if (job_stats == NULL) {
5847917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "entry_restored: jstat is NULL");
5857917SReza.Sabdar@Sun.COM 		return (0);
5867917SReza.Sabdar@Sun.COM 	}
5877917SReza.Sabdar@Sun.COM 	cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks;
5887917SReza.Sabdar@Sun.COM 	if (cbp == NULL) {
5897917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "entry_restored is NULL");
5907917SReza.Sabdar@Sun.COM 		return (0);
5917917SReza.Sabdar@Sun.COM 	}
5927917SReza.Sabdar@Sun.COM 	return (*cbp->fh_logpname)(cbp, name, 0, (longlong_t)pos);
5937917SReza.Sabdar@Sun.COM }
5947917SReza.Sabdar@Sun.COM /*
5957917SReza.Sabdar@Sun.COM  * NDMP support ends here.
5967917SReza.Sabdar@Sun.COM  */
5977917SReza.Sabdar@Sun.COM 
5987917SReza.Sabdar@Sun.COM /*
5997917SReza.Sabdar@Sun.COM  * Function: tlm_cat_path
6007917SReza.Sabdar@Sun.COM  * Concatenates two path names
6017917SReza.Sabdar@Sun.COM  * or directory name and file name
6027917SReza.Sabdar@Sun.COM  * into a buffer passed by the caller. A slash
6037917SReza.Sabdar@Sun.COM  * is inserted if required. Buffer is assumed
6047917SReza.Sabdar@Sun.COM  * to hold PATH_MAX characters.
6057917SReza.Sabdar@Sun.COM  *
6067917SReza.Sabdar@Sun.COM  * Parameters:
6077917SReza.Sabdar@Sun.COM  *	char *buf	- buffer to write new dir/name string
6087917SReza.Sabdar@Sun.COM  *	char *dir	- directory name
6097917SReza.Sabdar@Sun.COM  *	char *name	- file name
6107917SReza.Sabdar@Sun.COM  *
6117917SReza.Sabdar@Sun.COM  * Returns:
6127917SReza.Sabdar@Sun.COM  *	TRUE		- No errors. buf contains the dir/name string
6137917SReza.Sabdar@Sun.COM  *	FALSE		- Error. buf is not modified.
6147917SReza.Sabdar@Sun.COM  */
6157917SReza.Sabdar@Sun.COM boolean_t
tlm_cat_path(char * buf,char * dir,char * name)6167917SReza.Sabdar@Sun.COM tlm_cat_path(char *buf, char *dir, char *name)
6177917SReza.Sabdar@Sun.COM {
6187917SReza.Sabdar@Sun.COM 	char *fmt;
6197917SReza.Sabdar@Sun.COM 	int dirlen = strlen(dir);
6207917SReza.Sabdar@Sun.COM 	int filelen = strlen(name);
6217917SReza.Sabdar@Sun.COM 
6227917SReza.Sabdar@Sun.COM 	if ((dirlen + filelen + 1) >= PATH_MAX) {
6237917SReza.Sabdar@Sun.COM 		return (FALSE);
6247917SReza.Sabdar@Sun.COM 	}
6257917SReza.Sabdar@Sun.COM 
6267917SReza.Sabdar@Sun.COM 	if (*dir == '\0' || *name == '\0' || dir[dirlen - 1] == '/' ||
6277917SReza.Sabdar@Sun.COM 	    *name == '/') {
6287917SReza.Sabdar@Sun.COM 		fmt = "%s%s";
6297917SReza.Sabdar@Sun.COM 	} else {
6307917SReza.Sabdar@Sun.COM 		fmt = "%s/%s";
6317917SReza.Sabdar@Sun.COM 	}
6327917SReza.Sabdar@Sun.COM 
6337917SReza.Sabdar@Sun.COM 	/* check for ".../" and "/...." */
6347917SReza.Sabdar@Sun.COM 	if ((dirlen > 0) && (dir[dirlen - 1] == '/') && (*name == '/'))
6357917SReza.Sabdar@Sun.COM 		name += strspn(name, "/");
6367917SReza.Sabdar@Sun.COM 
6377917SReza.Sabdar@Sun.COM 	/* LINTED variable format */
6387917SReza.Sabdar@Sun.COM 	(void) snprintf(buf, TLM_MAX_PATH_NAME, fmt, dir, name);
6397917SReza.Sabdar@Sun.COM 
6407917SReza.Sabdar@Sun.COM 	return (TRUE);
6417917SReza.Sabdar@Sun.COM }
6427917SReza.Sabdar@Sun.COM 
6437917SReza.Sabdar@Sun.COM /*
6447917SReza.Sabdar@Sun.COM  * Get the checkpoint (snapshot) creation time.
6457917SReza.Sabdar@Sun.COM  * This is necessary to check for checkpoints not being stale.
6467917SReza.Sabdar@Sun.COM  */
6477917SReza.Sabdar@Sun.COM int
tlm_get_chkpnt_time(char * path,int auto_checkpoint,time_t * tp,char * jname)6487917SReza.Sabdar@Sun.COM tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname)
6497917SReza.Sabdar@Sun.COM {
6507917SReza.Sabdar@Sun.COM 	char volname[TLM_VOLNAME_MAX_LENGTH];
6517917SReza.Sabdar@Sun.COM 	char chk_name[PATH_MAX];
6527917SReza.Sabdar@Sun.COM 	char *cp_nm;
6537917SReza.Sabdar@Sun.COM 
6547917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "path [%s] auto_checkpoint: %d",
6557917SReza.Sabdar@Sun.COM 	    path, auto_checkpoint);
6567917SReza.Sabdar@Sun.COM 
6577917SReza.Sabdar@Sun.COM 	if (path == NULL || *path == '\0' || tp == NULL)
6587917SReza.Sabdar@Sun.COM 		return (-1);
6597917SReza.Sabdar@Sun.COM 
6607917SReza.Sabdar@Sun.COM 	if (get_zfsvolname(volname, TLM_VOLNAME_MAX_LENGTH,
6617917SReza.Sabdar@Sun.COM 	    path) == -1)
6627917SReza.Sabdar@Sun.COM 		return (-1);
6637917SReza.Sabdar@Sun.COM 
6647917SReza.Sabdar@Sun.COM 	if (auto_checkpoint) {
6657917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "volname [%s]", volname);
66612186SJanice.Chang@Sun.COM 		(void) snprintf(chk_name, PATH_MAX, "%s", jname);
6677917SReza.Sabdar@Sun.COM 		return (chkpnt_creationtime_bypattern(volname, chk_name, tp));
6687917SReza.Sabdar@Sun.COM 	}
6697917SReza.Sabdar@Sun.COM 	cp_nm = strchr(volname, '@');
6707917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "volname [%s] cp_nm [%s]", volname, cp_nm);
6717917SReza.Sabdar@Sun.COM 
6727917SReza.Sabdar@Sun.COM 	return (chkpnt_creationtime_bypattern(volname, cp_nm, tp));
6737917SReza.Sabdar@Sun.COM }
6747917SReza.Sabdar@Sun.COM 
6757917SReza.Sabdar@Sun.COM /*
6767917SReza.Sabdar@Sun.COM  * Release an array of pointers and the pointers themselves.
6777917SReza.Sabdar@Sun.COM  */
6787917SReza.Sabdar@Sun.COM void
tlm_release_list(char ** lpp)6797917SReza.Sabdar@Sun.COM tlm_release_list(char **lpp)
6807917SReza.Sabdar@Sun.COM {
6817917SReza.Sabdar@Sun.COM 	char **save;
6827917SReza.Sabdar@Sun.COM 
6837917SReza.Sabdar@Sun.COM 	if ((save = lpp) == 0)
6847917SReza.Sabdar@Sun.COM 		return;
6857917SReza.Sabdar@Sun.COM 
6867917SReza.Sabdar@Sun.COM 	while (*lpp)
6877917SReza.Sabdar@Sun.COM 		free(*lpp++);
6887917SReza.Sabdar@Sun.COM 
6897917SReza.Sabdar@Sun.COM 	free(save);
6907917SReza.Sabdar@Sun.COM }
6917917SReza.Sabdar@Sun.COM 
6927917SReza.Sabdar@Sun.COM /*
6937917SReza.Sabdar@Sun.COM  * Print the list of array of strings in the backup log
6947917SReza.Sabdar@Sun.COM  */
6957917SReza.Sabdar@Sun.COM void
tlm_log_list(char * title,char ** lpp)6967917SReza.Sabdar@Sun.COM tlm_log_list(char *title, char **lpp)
6977917SReza.Sabdar@Sun.COM {
6987917SReza.Sabdar@Sun.COM 	int i;
6997917SReza.Sabdar@Sun.COM 
7007917SReza.Sabdar@Sun.COM 	if (!lpp)
7017917SReza.Sabdar@Sun.COM 		return;
7027917SReza.Sabdar@Sun.COM 
7037917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "%s:", title);
7047917SReza.Sabdar@Sun.COM 
7057917SReza.Sabdar@Sun.COM 	for (i = 0; *lpp; lpp++, i++)
7067917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "%d: [%s]", i, *lpp);
7077917SReza.Sabdar@Sun.COM }
7087917SReza.Sabdar@Sun.COM 
7097917SReza.Sabdar@Sun.COM /*
7107917SReza.Sabdar@Sun.COM  * Insert the backup snapshot name into the path.
7117917SReza.Sabdar@Sun.COM  *
7127917SReza.Sabdar@Sun.COM  * Input:
71312186SJanice.Chang@Sun.COM  * 	name: Original path name.
7147917SReza.Sabdar@Sun.COM  *
7157917SReza.Sabdar@Sun.COM  * Output:
71612186SJanice.Chang@Sun.COM  * 	name: Original name modified to include a snapshot.
7177917SReza.Sabdar@Sun.COM  *
7187917SReza.Sabdar@Sun.COM  * Returns:
71912186SJanice.Chang@Sun.COM  * 	Original name modified to include a snapshot.
7207917SReza.Sabdar@Sun.COM  */
7217917SReza.Sabdar@Sun.COM char *
tlm_build_snapshot_name(char * name,char * sname,char * jname)7227917SReza.Sabdar@Sun.COM tlm_build_snapshot_name(char *name, char *sname, char *jname)
7237917SReza.Sabdar@Sun.COM {
7247917SReza.Sabdar@Sun.COM 	zfs_handle_t *zhp;
7257917SReza.Sabdar@Sun.COM 	char *rest;
7267917SReza.Sabdar@Sun.COM 	char volname[ZFS_MAXNAMELEN];
7277917SReza.Sabdar@Sun.COM 	char mountpoint[PATH_MAX];
7287917SReza.Sabdar@Sun.COM 
7297917SReza.Sabdar@Sun.COM 	if (get_zfsvolname(volname, ZFS_MAXNAMELEN, name) == -1)
7307917SReza.Sabdar@Sun.COM 		goto notzfs;
7317917SReza.Sabdar@Sun.COM 
7327917SReza.Sabdar@Sun.COM 	(void) mutex_lock(&zlib_mtx);
7337917SReza.Sabdar@Sun.COM 	if ((zlibh == NULL) ||
7347917SReza.Sabdar@Sun.COM 	    (zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == NULL) {
7357917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
7367917SReza.Sabdar@Sun.COM 		goto notzfs;
7377917SReza.Sabdar@Sun.COM 	}
7387917SReza.Sabdar@Sun.COM 
7397917SReza.Sabdar@Sun.COM 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, PATH_MAX, NULL,
7407917SReza.Sabdar@Sun.COM 	    NULL, 0, B_FALSE) != 0) {
7417917SReza.Sabdar@Sun.COM 		zfs_close(zhp);
7427917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
7437917SReza.Sabdar@Sun.COM 		goto notzfs;
7447917SReza.Sabdar@Sun.COM 	}
7457917SReza.Sabdar@Sun.COM 
7467917SReza.Sabdar@Sun.COM 	zfs_close(zhp);
7477917SReza.Sabdar@Sun.COM 	(void) mutex_unlock(&zlib_mtx);
7487917SReza.Sabdar@Sun.COM 
7497917SReza.Sabdar@Sun.COM 	rest = name + strlen(mountpoint);
75012186SJanice.Chang@Sun.COM 	(void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint,
7517917SReza.Sabdar@Sun.COM 	    TLM_SNAPSHOT_DIR, jname, rest);
7527917SReza.Sabdar@Sun.COM 
7537917SReza.Sabdar@Sun.COM 	return (sname);
7547917SReza.Sabdar@Sun.COM 
7557917SReza.Sabdar@Sun.COM notzfs:
7567917SReza.Sabdar@Sun.COM 	(void) strlcpy(sname, name, TLM_MAX_PATH_NAME);
7577917SReza.Sabdar@Sun.COM 	return (sname);
7587917SReza.Sabdar@Sun.COM }
7597917SReza.Sabdar@Sun.COM 
7607917SReza.Sabdar@Sun.COM /*
7617917SReza.Sabdar@Sun.COM  * Remove the checkpoint from a path name.
7627917SReza.Sabdar@Sun.COM  *
7637917SReza.Sabdar@Sun.COM  * Input:
7647917SReza.Sabdar@Sun.COM  * 	name: Full pathname with checkpoint embeded.
7657917SReza.Sabdar@Sun.COM  *
7667917SReza.Sabdar@Sun.COM  * Output:
7677917SReza.Sabdar@Sun.COM  * 	unchkp_name: real pathname with no checkpoint.
7687917SReza.Sabdar@Sun.COM  *
7697917SReza.Sabdar@Sun.COM  * Returns:
7707917SReza.Sabdar@Sun.COM  *	Pointer to the un-checkpointed path.
7717917SReza.Sabdar@Sun.COM  */
7727917SReza.Sabdar@Sun.COM char *
tlm_remove_checkpoint(char * name,char * unchkp_name)7737917SReza.Sabdar@Sun.COM tlm_remove_checkpoint(char *name, char *unchkp_name)
7747917SReza.Sabdar@Sun.COM {
7757917SReza.Sabdar@Sun.COM 	char *cp;
7767917SReza.Sabdar@Sun.COM 	int i;
7777917SReza.Sabdar@Sun.COM 	int plen;
7787917SReza.Sabdar@Sun.COM 
7797917SReza.Sabdar@Sun.COM 	unchkp_name[0] = name[0];
7807917SReza.Sabdar@Sun.COM 	plen = strlen(TLM_SNAPSHOT_PREFIX);
7817917SReza.Sabdar@Sun.COM 	for (i = 1; i <= TLM_VOLNAME_MAX_LENGTH + 1; i++) {
7827917SReza.Sabdar@Sun.COM 		switch (name[i]) {
7837917SReza.Sabdar@Sun.COM 		case '.':
7847917SReza.Sabdar@Sun.COM 			if (strncmp(&name[i], TLM_SNAPSHOT_PREFIX,
7857917SReza.Sabdar@Sun.COM 			    plen) == 0) {
7867917SReza.Sabdar@Sun.COM 				unchkp_name[i] = '\0';
7877917SReza.Sabdar@Sun.COM 				i += plen;
7887917SReza.Sabdar@Sun.COM 				if (name[i] == '\0') {
7897917SReza.Sabdar@Sun.COM 					/*
7907917SReza.Sabdar@Sun.COM 					 * name == "/v1.chkpnt"
7917917SReza.Sabdar@Sun.COM 					 */
7927917SReza.Sabdar@Sun.COM 					return (unchkp_name);
7937917SReza.Sabdar@Sun.COM 				}
7947917SReza.Sabdar@Sun.COM 				if ((cp = strchr(&name[++i], '/')) != NULL) {
7957917SReza.Sabdar@Sun.COM 					(void) strlcat(unchkp_name, cp,
7967917SReza.Sabdar@Sun.COM 					    TLM_VOLNAME_MAX_LENGTH + 1);
7977917SReza.Sabdar@Sun.COM 				}
7987917SReza.Sabdar@Sun.COM 				return (unchkp_name);
7997917SReza.Sabdar@Sun.COM 			} else {
8007917SReza.Sabdar@Sun.COM 				unchkp_name[i] = name[i];
8017917SReza.Sabdar@Sun.COM 			}
8027917SReza.Sabdar@Sun.COM 			break;
8037917SReza.Sabdar@Sun.COM 		case '/':
8047917SReza.Sabdar@Sun.COM 			return (name);
8057917SReza.Sabdar@Sun.COM 		case 0:
8067917SReza.Sabdar@Sun.COM 			return (name);
8077917SReza.Sabdar@Sun.COM 		default:
8087917SReza.Sabdar@Sun.COM 			unchkp_name[i] = name[i];
8097917SReza.Sabdar@Sun.COM 			break;
8107917SReza.Sabdar@Sun.COM 		}
8117917SReza.Sabdar@Sun.COM 	}
8127917SReza.Sabdar@Sun.COM 	return (name);
8137917SReza.Sabdar@Sun.COM }
8147917SReza.Sabdar@Sun.COM 
8157917SReza.Sabdar@Sun.COM /*
8167917SReza.Sabdar@Sun.COM  * see if we should exclude this file.
8177917SReza.Sabdar@Sun.COM  */
8187917SReza.Sabdar@Sun.COM boolean_t
tlm_is_excluded(char * dir,char * name,char ** excl_files)8197917SReza.Sabdar@Sun.COM tlm_is_excluded(char *dir, char *name, char **excl_files)
8207917SReza.Sabdar@Sun.COM {
8217917SReza.Sabdar@Sun.COM 	int	i;
8227917SReza.Sabdar@Sun.COM 	char	full_name[TLM_MAX_PATH_NAME];
8237917SReza.Sabdar@Sun.COM 
8247917SReza.Sabdar@Sun.COM 	if (!dir || !name || !excl_files)
8257917SReza.Sabdar@Sun.COM 		return (FALSE);
8267917SReza.Sabdar@Sun.COM 
8277917SReza.Sabdar@Sun.COM 	if (!tlm_cat_path(full_name, dir, name)) {
8287917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]",
8297917SReza.Sabdar@Sun.COM 		    dir, name);
8307917SReza.Sabdar@Sun.COM 		return (FALSE);
8317917SReza.Sabdar@Sun.COM 	}
8327917SReza.Sabdar@Sun.COM 	for (i = 0; excl_files[i] != 0; i++) {
8337917SReza.Sabdar@Sun.COM 		if (match(excl_files[i], full_name)) {
8347917SReza.Sabdar@Sun.COM 			return (TRUE);
8357917SReza.Sabdar@Sun.COM 		}
8367917SReza.Sabdar@Sun.COM 	}
8377917SReza.Sabdar@Sun.COM 	return (FALSE);
8387917SReza.Sabdar@Sun.COM }
8397917SReza.Sabdar@Sun.COM 
8407917SReza.Sabdar@Sun.COM /*
8417917SReza.Sabdar@Sun.COM  * Check if the path is too long
8427917SReza.Sabdar@Sun.COM  */
8437917SReza.Sabdar@Sun.COM boolean_t
tlm_is_too_long(int checkpointed,char * dir,char * nm)8447917SReza.Sabdar@Sun.COM tlm_is_too_long(int checkpointed, char *dir, char *nm)
8457917SReza.Sabdar@Sun.COM {
8467917SReza.Sabdar@Sun.COM 	int nlen, tot;
8477917SReza.Sabdar@Sun.COM 
8487917SReza.Sabdar@Sun.COM 	tot = 0;
8497917SReza.Sabdar@Sun.COM 	if (dir)
8507917SReza.Sabdar@Sun.COM 		tot += strlen(dir);
8517917SReza.Sabdar@Sun.COM 	if (checkpointed)
8527917SReza.Sabdar@Sun.COM 		tot += strlen(TLM_SNAPSHOT_DIR) + 1;
8537917SReza.Sabdar@Sun.COM 	if (nm) {
8547917SReza.Sabdar@Sun.COM 		if ((nlen = strlen(nm)) > 0)
8557917SReza.Sabdar@Sun.COM 			tot += nlen + 1;
8567917SReza.Sabdar@Sun.COM 	}
8577917SReza.Sabdar@Sun.COM 	return ((tot >= PATH_MAX) ? TRUE : FALSE);
8587917SReza.Sabdar@Sun.COM }
8597917SReza.Sabdar@Sun.COM 
8607917SReza.Sabdar@Sun.COM /*
8617917SReza.Sabdar@Sun.COM  * Get the data offset of inside the buffer
8627917SReza.Sabdar@Sun.COM  */
8637917SReza.Sabdar@Sun.COM longlong_t
tlm_get_data_offset(tlm_cmd_t * lcmds)8647917SReza.Sabdar@Sun.COM tlm_get_data_offset(tlm_cmd_t *lcmds)
8657917SReza.Sabdar@Sun.COM {
8667917SReza.Sabdar@Sun.COM 	if (!lcmds)
8677917SReza.Sabdar@Sun.COM 		return (0LL);
8687917SReza.Sabdar@Sun.COM 
8697917SReza.Sabdar@Sun.COM 	return (lcmds->tc_buffers->tbs_offset);
8707917SReza.Sabdar@Sun.COM }
8717917SReza.Sabdar@Sun.COM 
8727917SReza.Sabdar@Sun.COM /*
8737917SReza.Sabdar@Sun.COM  * Enable the barcode capability on the library
8747917SReza.Sabdar@Sun.COM  */
8757917SReza.Sabdar@Sun.COM void
tlm_enable_barcode(int l)8767917SReza.Sabdar@Sun.COM tlm_enable_barcode(int l)
8777917SReza.Sabdar@Sun.COM {
8787917SReza.Sabdar@Sun.COM 	tlm_library_t *lp;
8797917SReza.Sabdar@Sun.COM 
8807917SReza.Sabdar@Sun.COM 	if ((lp = tlm_library(l))) {
8817917SReza.Sabdar@Sun.COM 		lp->tl_capability_barcodes = TRUE;
8827917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
8837917SReza.Sabdar@Sun.COM 		    "Barcode capability on library %d enabled.", l);
8847917SReza.Sabdar@Sun.COM 	}
8857917SReza.Sabdar@Sun.COM }
8867917SReza.Sabdar@Sun.COM 
8877917SReza.Sabdar@Sun.COM /*
8887917SReza.Sabdar@Sun.COM  * SASD SCSI support
8897917SReza.Sabdar@Sun.COM  */
8907917SReza.Sabdar@Sun.COM static scsi_adapter_t my_sa;
8917917SReza.Sabdar@Sun.COM static int sasd_drive_count = 0;
8927917SReza.Sabdar@Sun.COM static scsi_sasd_drive_t *scsi_sasd_drives[128];
8937917SReza.Sabdar@Sun.COM 
8947917SReza.Sabdar@Sun.COM /*
8957917SReza.Sabdar@Sun.COM  * Count of SCSI devices
8967917SReza.Sabdar@Sun.COM  */
8977917SReza.Sabdar@Sun.COM int
sasd_dev_count(void)8987917SReza.Sabdar@Sun.COM sasd_dev_count(void)
8997917SReza.Sabdar@Sun.COM {
9007917SReza.Sabdar@Sun.COM 	return (sasd_drive_count);
9017917SReza.Sabdar@Sun.COM }
9027917SReza.Sabdar@Sun.COM 
9037917SReza.Sabdar@Sun.COM /*
9047917SReza.Sabdar@Sun.COM  * Return the SCSI device name
9057917SReza.Sabdar@Sun.COM  */
9067917SReza.Sabdar@Sun.COM char *
sasd_slink_name(scsi_link_t * slink)9077917SReza.Sabdar@Sun.COM sasd_slink_name(scsi_link_t *slink)
9087917SReza.Sabdar@Sun.COM {
9097917SReza.Sabdar@Sun.COM 	int i;
9107917SReza.Sabdar@Sun.COM 
9117917SReza.Sabdar@Sun.COM 	for (i = 0; i < sasd_drive_count; i++) {
9127917SReza.Sabdar@Sun.COM 		if (&scsi_sasd_drives[i]->ss_slink == slink)
9137917SReza.Sabdar@Sun.COM 			return (scsi_sasd_drives[i]->ss_sd.sd_name);
9147917SReza.Sabdar@Sun.COM 	}
9157917SReza.Sabdar@Sun.COM 	return (NULL);
9167917SReza.Sabdar@Sun.COM }
9177917SReza.Sabdar@Sun.COM 
9187917SReza.Sabdar@Sun.COM /*
9197917SReza.Sabdar@Sun.COM  * Return the SCSI drive structure
9207917SReza.Sabdar@Sun.COM  */
9217917SReza.Sabdar@Sun.COM sasd_drive_t *
sasd_slink_drive(scsi_link_t * slink)9227917SReza.Sabdar@Sun.COM sasd_slink_drive(scsi_link_t *slink)
9237917SReza.Sabdar@Sun.COM {
9247917SReza.Sabdar@Sun.COM 	int i;
9257917SReza.Sabdar@Sun.COM 
9267917SReza.Sabdar@Sun.COM 	for (i = 0; i < sasd_drive_count; i++) {
9277917SReza.Sabdar@Sun.COM 		if (&scsi_sasd_drives[i]->ss_slink == slink)
9287917SReza.Sabdar@Sun.COM 			return (&scsi_sasd_drives[i]->ss_sd);
9297917SReza.Sabdar@Sun.COM 	}
9307917SReza.Sabdar@Sun.COM 	return (NULL);
9317917SReza.Sabdar@Sun.COM }
9327917SReza.Sabdar@Sun.COM 
9337917SReza.Sabdar@Sun.COM /*
9347917SReza.Sabdar@Sun.COM  * Return the SCSI link pointer for the given index
9357917SReza.Sabdar@Sun.COM  */
9367917SReza.Sabdar@Sun.COM scsi_link_t *
sasd_dev_slink(int entry)9377917SReza.Sabdar@Sun.COM sasd_dev_slink(int entry)
9387917SReza.Sabdar@Sun.COM {
9397917SReza.Sabdar@Sun.COM 	scsi_link_t *rv;
9407917SReza.Sabdar@Sun.COM 
9417917SReza.Sabdar@Sun.COM 	if (entry >= 0 && entry < sasd_drive_count)
9427917SReza.Sabdar@Sun.COM 		rv = &scsi_sasd_drives[entry]->ss_slink;
9437917SReza.Sabdar@Sun.COM 	else
9447917SReza.Sabdar@Sun.COM 		rv = NULL;
9457917SReza.Sabdar@Sun.COM 
9467917SReza.Sabdar@Sun.COM 	return (rv);
9477917SReza.Sabdar@Sun.COM }
9487917SReza.Sabdar@Sun.COM 
9497917SReza.Sabdar@Sun.COM /*
9507917SReza.Sabdar@Sun.COM  * Return the SCSI drive for the given index
9517917SReza.Sabdar@Sun.COM  */
9527917SReza.Sabdar@Sun.COM sasd_drive_t *
sasd_drive(int entry)9537917SReza.Sabdar@Sun.COM sasd_drive(int entry)
9547917SReza.Sabdar@Sun.COM {
9557917SReza.Sabdar@Sun.COM 	sasd_drive_t *rv;
9567917SReza.Sabdar@Sun.COM 
9577917SReza.Sabdar@Sun.COM 	if (entry >= 0 && entry < sasd_drive_count)
9587917SReza.Sabdar@Sun.COM 		rv = &scsi_sasd_drives[entry]->ss_sd;
9597917SReza.Sabdar@Sun.COM 	else
9607917SReza.Sabdar@Sun.COM 		rv = NULL;
9617917SReza.Sabdar@Sun.COM 
9627917SReza.Sabdar@Sun.COM 	return (rv);
9637917SReza.Sabdar@Sun.COM }
9647917SReza.Sabdar@Sun.COM 
9657917SReza.Sabdar@Sun.COM /*
9667917SReza.Sabdar@Sun.COM  * Attach the SCSI device by updating the structures
9677917SReza.Sabdar@Sun.COM  */
9687917SReza.Sabdar@Sun.COM void
scsi_sasd_attach(scsi_adapter_t * sa,int sid,int lun,char * name,int type)9697917SReza.Sabdar@Sun.COM scsi_sasd_attach(scsi_adapter_t *sa, int sid, int lun, char *name,
9707917SReza.Sabdar@Sun.COM     int type)
9717917SReza.Sabdar@Sun.COM {
9727917SReza.Sabdar@Sun.COM 	scsi_link_t *sl, *next;
9737917SReza.Sabdar@Sun.COM 	scsi_sasd_drive_t *ssd;
9747917SReza.Sabdar@Sun.COM 
9757917SReza.Sabdar@Sun.COM 	ssd = ndmp_malloc(sizeof (scsi_sasd_drive_t));
9767917SReza.Sabdar@Sun.COM 	if (ssd == NULL)
9777917SReza.Sabdar@Sun.COM 		return;
9787917SReza.Sabdar@Sun.COM 
9797917SReza.Sabdar@Sun.COM 	scsi_sasd_drives[sasd_drive_count++] = ssd;
9807917SReza.Sabdar@Sun.COM 
9817917SReza.Sabdar@Sun.COM 	switch (type) {
9827917SReza.Sabdar@Sun.COM 	case DTYPE_CHANGER:
9837917SReza.Sabdar@Sun.COM 		(void) snprintf(ssd->ss_sd.sd_name,
9847917SReza.Sabdar@Sun.COM 		    sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_CHANGER_DIR,
9857917SReza.Sabdar@Sun.COM 		    name);
9867917SReza.Sabdar@Sun.COM 		break;
9877917SReza.Sabdar@Sun.COM 	case DTYPE_SEQUENTIAL:
9887917SReza.Sabdar@Sun.COM 		(void) snprintf(ssd->ss_sd.sd_name,
9897917SReza.Sabdar@Sun.COM 		    sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_TAPE_DIR, name);
9907917SReza.Sabdar@Sun.COM 		break;
9917917SReza.Sabdar@Sun.COM 	}
9927917SReza.Sabdar@Sun.COM 
9937917SReza.Sabdar@Sun.COM 	sl = &ssd->ss_slink;
9947917SReza.Sabdar@Sun.COM 	sl->sl_type = type;
9957917SReza.Sabdar@Sun.COM 	sl->sl_sa = sa;
9967917SReza.Sabdar@Sun.COM 	sl->sl_lun = lun;
9977917SReza.Sabdar@Sun.COM 	sl->sl_sid = sid;
9987917SReza.Sabdar@Sun.COM 	sl->sl_requested_max_active = 1;
9997917SReza.Sabdar@Sun.COM 
10007917SReza.Sabdar@Sun.COM 	/* Insert slink */
10017917SReza.Sabdar@Sun.COM 	next = sa->sa_link_head.sl_next;
10027917SReza.Sabdar@Sun.COM 	sa->sa_link_head.sl_next = sl;
10037917SReza.Sabdar@Sun.COM 	sl->sl_next = next;
10047917SReza.Sabdar@Sun.COM }
10057917SReza.Sabdar@Sun.COM 
10067917SReza.Sabdar@Sun.COM /*
10077917SReza.Sabdar@Sun.COM  * Go through the attached devices and detect the tape
10087917SReza.Sabdar@Sun.COM  * and robot by checking the /dev entries
10097917SReza.Sabdar@Sun.COM  */
10107917SReza.Sabdar@Sun.COM int
probe_scsi(void)10117917SReza.Sabdar@Sun.COM probe_scsi(void)
10127917SReza.Sabdar@Sun.COM {
10137917SReza.Sabdar@Sun.COM 	DIR *dirp;
10147917SReza.Sabdar@Sun.COM 	struct dirent *dp;
10157917SReza.Sabdar@Sun.COM 	scsi_adapter_t *sa = &my_sa;
10167917SReza.Sabdar@Sun.COM 	char *p;
10177917SReza.Sabdar@Sun.COM 	int lun = 0;
10187917SReza.Sabdar@Sun.COM 	int sid = 0;
1019*13051SJanice.Chang@Sun.COM 	char *drive_type;
10207917SReza.Sabdar@Sun.COM 
10217917SReza.Sabdar@Sun.COM 	/* Initialize the scsi adapter link */
10227917SReza.Sabdar@Sun.COM 	sa->sa_link_head.sl_next = &sa->sa_link_head;
10237917SReza.Sabdar@Sun.COM 
10247917SReza.Sabdar@Sun.COM 	/* Scan for the changer */
10257917SReza.Sabdar@Sun.COM 	dirp = opendir(SCSI_CHANGER_DIR);
10267917SReza.Sabdar@Sun.COM 	if (dirp == NULL) {
10277917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10287917SReza.Sabdar@Sun.COM 		    "Changer directory read error %s", SCSI_CHANGER_DIR);
10297917SReza.Sabdar@Sun.COM 	} else {
10307917SReza.Sabdar@Sun.COM 		while ((dp = readdir(dirp)) != NULL) {
10317917SReza.Sabdar@Sun.COM 			if ((strcmp(dp->d_name, ".") == 0) ||
10327917SReza.Sabdar@Sun.COM 			    (strcmp(dp->d_name, "..") == 0))
10337917SReza.Sabdar@Sun.COM 				continue;
10347917SReza.Sabdar@Sun.COM 
10357917SReza.Sabdar@Sun.COM 			if ((p = strchr(dp->d_name, 'd')) != NULL) {
10367917SReza.Sabdar@Sun.COM 				lun = atoi(++p);
10377917SReza.Sabdar@Sun.COM 				p = strchr(dp->d_name, 't');
10387917SReza.Sabdar@Sun.COM 				sid = atoi(++p);
10397917SReza.Sabdar@Sun.COM 			}
10407917SReza.Sabdar@Sun.COM 			else
10417917SReza.Sabdar@Sun.COM 				sid = atoi(dp->d_name);
10427917SReza.Sabdar@Sun.COM 
10437917SReza.Sabdar@Sun.COM 			scsi_sasd_attach(sa, 0, lun, dp->d_name,
10447917SReza.Sabdar@Sun.COM 			    DTYPE_CHANGER);
10457917SReza.Sabdar@Sun.COM 		}
10467917SReza.Sabdar@Sun.COM 		(void) closedir(dirp);
10477917SReza.Sabdar@Sun.COM 	}
10487917SReza.Sabdar@Sun.COM 
10497917SReza.Sabdar@Sun.COM 	/* Scan for tape drives */
10507917SReza.Sabdar@Sun.COM 	dirp = opendir(SCSI_TAPE_DIR);
10517917SReza.Sabdar@Sun.COM 	if (dirp == NULL) {
10527917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG,
10537917SReza.Sabdar@Sun.COM 		    "Tape directory read error %s", SCSI_TAPE_DIR);
10547917SReza.Sabdar@Sun.COM 	} else {
1055*13051SJanice.Chang@Sun.COM 		drive_type = ndmpd_get_prop(NDMP_DRIVE_TYPE);
1056*13051SJanice.Chang@Sun.COM 
1057*13051SJanice.Chang@Sun.COM 		if ((strcasecmp(drive_type, "sysv") != 0) &&
1058*13051SJanice.Chang@Sun.COM 		    (strcasecmp(drive_type, "bsd") != 0)) {
1059*13051SJanice.Chang@Sun.COM 			NDMP_LOG(LOG_ERR, "Invalid ndmpd/drive-type value. "
1060*13051SJanice.Chang@Sun.COM 			    "Valid values are 'sysv' and 'bsd'.");
1061*13051SJanice.Chang@Sun.COM 			return (-1);
1062*13051SJanice.Chang@Sun.COM 		}
1063*13051SJanice.Chang@Sun.COM 
10647917SReza.Sabdar@Sun.COM 		while ((dp = readdir(dirp)) != NULL) {
10657917SReza.Sabdar@Sun.COM 			if ((strcmp(dp->d_name, ".") == 0) ||
10667917SReza.Sabdar@Sun.COM 			    (strcmp(dp->d_name, "..") == 0))
10677917SReza.Sabdar@Sun.COM 				continue;
10687917SReza.Sabdar@Sun.COM 
10697917SReza.Sabdar@Sun.COM 			/* Skip special modes */
1070*13051SJanice.Chang@Sun.COM 			if (strpbrk(dp->d_name, "chlmu") != NULL)
10717917SReza.Sabdar@Sun.COM 				continue;
10727917SReza.Sabdar@Sun.COM 
10737917SReza.Sabdar@Sun.COM 			/* Pick the non-rewind device */
10747917SReza.Sabdar@Sun.COM 			if (strchr(dp->d_name, 'n') == NULL)
10757917SReza.Sabdar@Sun.COM 				continue;
10767917SReza.Sabdar@Sun.COM 
1077*13051SJanice.Chang@Sun.COM 			if (strcasecmp(drive_type, "sysv") == 0) {
1078*13051SJanice.Chang@Sun.COM 				if (strchr(dp->d_name, 'b') != NULL)
1079*13051SJanice.Chang@Sun.COM 					continue;
1080*13051SJanice.Chang@Sun.COM 			} else if (strcasecmp(drive_type, "bsd") == 0) {
1081*13051SJanice.Chang@Sun.COM 				if (strchr(dp->d_name, 'b') == NULL)
1082*13051SJanice.Chang@Sun.COM 					continue;
1083*13051SJanice.Chang@Sun.COM 			}
1084*13051SJanice.Chang@Sun.COM 
10857917SReza.Sabdar@Sun.COM 			sid = atoi(dp->d_name);
10867917SReza.Sabdar@Sun.COM 
10877917SReza.Sabdar@Sun.COM 			/*
10887917SReza.Sabdar@Sun.COM 			 * SCSI ID should match with the ID of the device
10897917SReza.Sabdar@Sun.COM 			 * (will be checked by SCSI get elements page later)
10907917SReza.Sabdar@Sun.COM 			 */
10917917SReza.Sabdar@Sun.COM 			scsi_sasd_attach(sa, sid, 0, dp->d_name,
10927917SReza.Sabdar@Sun.COM 			    DTYPE_SEQUENTIAL);
10937917SReza.Sabdar@Sun.COM 		}
10947917SReza.Sabdar@Sun.COM 		(void) closedir(dirp);
10957917SReza.Sabdar@Sun.COM 	}
10967917SReza.Sabdar@Sun.COM 
10977917SReza.Sabdar@Sun.COM 	return (0);
10987917SReza.Sabdar@Sun.COM }
10997917SReza.Sabdar@Sun.COM 
11007917SReza.Sabdar@Sun.COM /*
11017917SReza.Sabdar@Sun.COM  * Get the SCSI device type (tape, robot)
11027917SReza.Sabdar@Sun.COM  */
11037917SReza.Sabdar@Sun.COM /*ARGSUSED*/
11047917SReza.Sabdar@Sun.COM int
scsi_get_devtype(char * adapter,int sid,int lun)11057917SReza.Sabdar@Sun.COM scsi_get_devtype(char *adapter, int sid, int lun)
11067917SReza.Sabdar@Sun.COM {
11077917SReza.Sabdar@Sun.COM 	int rv;
11087917SReza.Sabdar@Sun.COM 	scsi_adapter_t *sa = &my_sa;
11097917SReza.Sabdar@Sun.COM 	scsi_link_t *sl, *sh;
11107917SReza.Sabdar@Sun.COM 
11117917SReza.Sabdar@Sun.COM 	rv = -1;
11127917SReza.Sabdar@Sun.COM 	sh = &sa->sa_link_head;
11137917SReza.Sabdar@Sun.COM 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
11147917SReza.Sabdar@Sun.COM 		if (sl->sl_sid == sid && sl->sl_lun == lun)
11157917SReza.Sabdar@Sun.COM 			rv = sl->sl_type;
11167917SReza.Sabdar@Sun.COM 
11177917SReza.Sabdar@Sun.COM 	return (rv);
11187917SReza.Sabdar@Sun.COM }
11197917SReza.Sabdar@Sun.COM 
11207917SReza.Sabdar@Sun.COM 
11217917SReza.Sabdar@Sun.COM /*
11227917SReza.Sabdar@Sun.COM  * Check if the SCSI device exists
11237917SReza.Sabdar@Sun.COM  */
11247917SReza.Sabdar@Sun.COM /*ARGSUSED*/
11257917SReza.Sabdar@Sun.COM int
scsi_dev_exists(char * adapter,int sid,int lun)11267917SReza.Sabdar@Sun.COM scsi_dev_exists(char *adapter, int sid, int lun)
11277917SReza.Sabdar@Sun.COM {
11287917SReza.Sabdar@Sun.COM 	scsi_adapter_t *sa = &my_sa;
11297917SReza.Sabdar@Sun.COM 	scsi_link_t *sl, *sh;
11307917SReza.Sabdar@Sun.COM 
11317917SReza.Sabdar@Sun.COM 	sh = &sa->sa_link_head;
11327917SReza.Sabdar@Sun.COM 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
11337917SReza.Sabdar@Sun.COM 		if (sl->sl_sid == sid && sl->sl_lun == lun)
11347917SReza.Sabdar@Sun.COM 			return (1);
11357917SReza.Sabdar@Sun.COM 	return (0);
11367917SReza.Sabdar@Sun.COM }
11377917SReza.Sabdar@Sun.COM 
11387917SReza.Sabdar@Sun.COM 
11397917SReza.Sabdar@Sun.COM /*
11407917SReza.Sabdar@Sun.COM  * Count of SCSI adapters
11417917SReza.Sabdar@Sun.COM  */
11427917SReza.Sabdar@Sun.COM int
scsi_get_adapter_count(void)11437917SReza.Sabdar@Sun.COM scsi_get_adapter_count(void)
11447917SReza.Sabdar@Sun.COM {
11457917SReza.Sabdar@Sun.COM 	/* Currently support one adapter only */
11467917SReza.Sabdar@Sun.COM 	return (1);
11477917SReza.Sabdar@Sun.COM }
11487917SReza.Sabdar@Sun.COM 
11497917SReza.Sabdar@Sun.COM /*
11507917SReza.Sabdar@Sun.COM  * Return the SCSI adapter structure
11517917SReza.Sabdar@Sun.COM  */
11527917SReza.Sabdar@Sun.COM /*ARGSUSED*/
11537917SReza.Sabdar@Sun.COM scsi_adapter_t *
scsi_get_adapter(int adapter)11547917SReza.Sabdar@Sun.COM scsi_get_adapter(int adapter)
11557917SReza.Sabdar@Sun.COM {
11567917SReza.Sabdar@Sun.COM 	return (&my_sa);
11577917SReza.Sabdar@Sun.COM }
11587917SReza.Sabdar@Sun.COM 
11597917SReza.Sabdar@Sun.COM /*
11607917SReza.Sabdar@Sun.COM  * IOCTL wrapper with retries
11617917SReza.Sabdar@Sun.COM  */
11627917SReza.Sabdar@Sun.COM int
tlm_ioctl(int fd,int cmd,void * data)11637917SReza.Sabdar@Sun.COM tlm_ioctl(int fd, int cmd, void *data)
11647917SReza.Sabdar@Sun.COM {
11657917SReza.Sabdar@Sun.COM 	int retries = 0;
11667917SReza.Sabdar@Sun.COM 
11677917SReza.Sabdar@Sun.COM 	NDMP_LOG(LOG_DEBUG, "tlm_ioctl fd %d cmd %d", fd, cmd);
11687917SReza.Sabdar@Sun.COM 	if (fd == 0 || data == NULL)
11697917SReza.Sabdar@Sun.COM 		return (EINVAL);
11707917SReza.Sabdar@Sun.COM 
11717917SReza.Sabdar@Sun.COM 	do {
11727917SReza.Sabdar@Sun.COM 		if (ioctl(fd, cmd, data) == 0)
11737917SReza.Sabdar@Sun.COM 			break;
11747917SReza.Sabdar@Sun.COM 
11757917SReza.Sabdar@Sun.COM 		if (errno != EIO && errno != 0) {
11767917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_ERR,
11777917SReza.Sabdar@Sun.COM 			    "Failed to send command to device: %m.");
11787917SReza.Sabdar@Sun.COM 			NDMP_LOG(LOG_DEBUG, "IOCTL error %d", errno);
11797917SReza.Sabdar@Sun.COM 			return (errno);
11807917SReza.Sabdar@Sun.COM 		}
11817917SReza.Sabdar@Sun.COM 		(void) sleep(1);
11827917SReza.Sabdar@Sun.COM 	} while (retries++ < MAXIORETRY);
11837917SReza.Sabdar@Sun.COM 
11847917SReza.Sabdar@Sun.COM 	return (0);
11857917SReza.Sabdar@Sun.COM }
11867917SReza.Sabdar@Sun.COM 
11877917SReza.Sabdar@Sun.COM /*
11887917SReza.Sabdar@Sun.COM  * Checkpoint or snapshot calls
11897917SReza.Sabdar@Sun.COM  */
11907917SReza.Sabdar@Sun.COM 
11917917SReza.Sabdar@Sun.COM /*
11927917SReza.Sabdar@Sun.COM  * Get the snapshot creation time
11937917SReza.Sabdar@Sun.COM  */
11947917SReza.Sabdar@Sun.COM int
chkpnt_creationtime_bypattern(char * volname,char * pattern,time_t * tp)11957917SReza.Sabdar@Sun.COM chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp)
11967917SReza.Sabdar@Sun.COM {
11977917SReza.Sabdar@Sun.COM 	char chk_name[PATH_MAX];
11987917SReza.Sabdar@Sun.COM 	zfs_handle_t *zhp;
11997917SReza.Sabdar@Sun.COM 	char *p;
12007917SReza.Sabdar@Sun.COM 
12017917SReza.Sabdar@Sun.COM 	if (!volname || !*volname)
12027917SReza.Sabdar@Sun.COM 		return (-1);
12037917SReza.Sabdar@Sun.COM 
12047917SReza.Sabdar@Sun.COM 	/* Should also return -1 if checkpoint not enabled */
12057917SReza.Sabdar@Sun.COM 
12067917SReza.Sabdar@Sun.COM 	/* Remove the leading slash */
12077917SReza.Sabdar@Sun.COM 	p = volname;
12087917SReza.Sabdar@Sun.COM 	while (*p == '/')
12097917SReza.Sabdar@Sun.COM 		p++;
12107917SReza.Sabdar@Sun.COM 
12117917SReza.Sabdar@Sun.COM 	(void) strlcpy(chk_name, p, PATH_MAX);
12127917SReza.Sabdar@Sun.COM 	(void) strlcat(chk_name, "@", PATH_MAX);
12137917SReza.Sabdar@Sun.COM 	(void) strlcat(chk_name, pattern, PATH_MAX);
12147917SReza.Sabdar@Sun.COM 
12157917SReza.Sabdar@Sun.COM 	(void) mutex_lock(&zlib_mtx);
12167917SReza.Sabdar@Sun.COM 	if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_DATASET)) == NULL) {
12177917SReza.Sabdar@Sun.COM 		NDMP_LOG(LOG_DEBUG, "chkpnt_creationtime: open %s failed",
12187917SReza.Sabdar@Sun.COM 		    chk_name);
12197917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
12207917SReza.Sabdar@Sun.COM 		return (-1);
12217917SReza.Sabdar@Sun.COM 	}
12227917SReza.Sabdar@Sun.COM 
12237917SReza.Sabdar@Sun.COM 	*tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
12247917SReza.Sabdar@Sun.COM 	zfs_close(zhp);
12257917SReza.Sabdar@Sun.COM 	(void) mutex_unlock(&zlib_mtx);
12267917SReza.Sabdar@Sun.COM 
12277917SReza.Sabdar@Sun.COM 	return (0);
12287917SReza.Sabdar@Sun.COM }
12297917SReza.Sabdar@Sun.COM 
12307917SReza.Sabdar@Sun.COM 
12317917SReza.Sabdar@Sun.COM /*
12327917SReza.Sabdar@Sun.COM  * Get the ZFS volume name out of the given path
12337917SReza.Sabdar@Sun.COM  */
12347917SReza.Sabdar@Sun.COM int
get_zfsvolname(char * volname,int len,char * path)12357917SReza.Sabdar@Sun.COM get_zfsvolname(char *volname, int len, char *path)
12367917SReza.Sabdar@Sun.COM {
12377917SReza.Sabdar@Sun.COM 	struct stat64 stbuf;
12387917SReza.Sabdar@Sun.COM 	struct extmnttab ent;
12397917SReza.Sabdar@Sun.COM 	FILE *mntfp;
12407917SReza.Sabdar@Sun.COM 	int rv;
12417917SReza.Sabdar@Sun.COM 
12427917SReza.Sabdar@Sun.COM 	*volname = '\0';
12437917SReza.Sabdar@Sun.COM 	if (stat64(path, &stbuf) != 0) {
12447917SReza.Sabdar@Sun.COM 		return (-1);
12457917SReza.Sabdar@Sun.COM 	}
12467917SReza.Sabdar@Sun.COM 
12477917SReza.Sabdar@Sun.COM 	if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
12487917SReza.Sabdar@Sun.COM 		return (-1);
12497917SReza.Sabdar@Sun.COM 	}
12507917SReza.Sabdar@Sun.COM 	while ((rv = getextmntent(mntfp, &ent, 0)) == 0) {
12517917SReza.Sabdar@Sun.COM 		if (makedevice(ent.mnt_major, ent.mnt_minor) ==
12527917SReza.Sabdar@Sun.COM 		    stbuf.st_dev)
12537917SReza.Sabdar@Sun.COM 			break;
12547917SReza.Sabdar@Sun.COM 	}
12557917SReza.Sabdar@Sun.COM 
12567917SReza.Sabdar@Sun.COM 	if (rv == 0 &&
12577917SReza.Sabdar@Sun.COM 	    strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0)
12587917SReza.Sabdar@Sun.COM 		(void) strlcpy(volname, ent.mnt_special, len);
12597917SReza.Sabdar@Sun.COM 	else
12607917SReza.Sabdar@Sun.COM 		rv = -1;
12617917SReza.Sabdar@Sun.COM 
12627917SReza.Sabdar@Sun.COM 	(void) fclose(mntfp);
12637917SReza.Sabdar@Sun.COM 	return (rv);
12647917SReza.Sabdar@Sun.COM }
12657917SReza.Sabdar@Sun.COM 
12667917SReza.Sabdar@Sun.COM 
12677917SReza.Sabdar@Sun.COM /*
12687917SReza.Sabdar@Sun.COM  * Check if the volume type is snapshot volume
12697917SReza.Sabdar@Sun.COM  */
12707917SReza.Sabdar@Sun.COM boolean_t
fs_is_chkpntvol(char * path)12717917SReza.Sabdar@Sun.COM fs_is_chkpntvol(char *path)
12727917SReza.Sabdar@Sun.COM {
12737917SReza.Sabdar@Sun.COM 	zfs_handle_t *zhp;
12747917SReza.Sabdar@Sun.COM 	char vol[ZFS_MAXNAMELEN];
12757917SReza.Sabdar@Sun.COM 
12767917SReza.Sabdar@Sun.COM 	if (!path || !*path)
12777917SReza.Sabdar@Sun.COM 		return (FALSE);
12787917SReza.Sabdar@Sun.COM 
12797917SReza.Sabdar@Sun.COM 	if (get_zfsvolname(vol, sizeof (vol), path) == -1)
12807917SReza.Sabdar@Sun.COM 		return (FALSE);
12817917SReza.Sabdar@Sun.COM 
12827917SReza.Sabdar@Sun.COM 	(void) mutex_lock(&zlib_mtx);
12837917SReza.Sabdar@Sun.COM 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
12847917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
12857917SReza.Sabdar@Sun.COM 		return (FALSE);
12867917SReza.Sabdar@Sun.COM 	}
12877917SReza.Sabdar@Sun.COM 
12887917SReza.Sabdar@Sun.COM 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
12897917SReza.Sabdar@Sun.COM 		zfs_close(zhp);
12907917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
12917917SReza.Sabdar@Sun.COM 		return (FALSE);
12927917SReza.Sabdar@Sun.COM 	}
12937917SReza.Sabdar@Sun.COM 	zfs_close(zhp);
12947917SReza.Sabdar@Sun.COM 	(void) mutex_unlock(&zlib_mtx);
12957917SReza.Sabdar@Sun.COM 
12967917SReza.Sabdar@Sun.COM 	return (TRUE);
12977917SReza.Sabdar@Sun.COM }
12987917SReza.Sabdar@Sun.COM 
12997917SReza.Sabdar@Sun.COM /*
13007917SReza.Sabdar@Sun.COM  * Check if the volume is capable of checkpoints
13017917SReza.Sabdar@Sun.COM  */
13027917SReza.Sabdar@Sun.COM boolean_t
fs_is_chkpnt_enabled(char * path)13037917SReza.Sabdar@Sun.COM fs_is_chkpnt_enabled(char *path)
13047917SReza.Sabdar@Sun.COM {
13057917SReza.Sabdar@Sun.COM 	zfs_handle_t *zhp;
13067917SReza.Sabdar@Sun.COM 	char vol[ZFS_MAXNAMELEN];
13077917SReza.Sabdar@Sun.COM 
13087917SReza.Sabdar@Sun.COM 	if (!path || !*path)
13097917SReza.Sabdar@Sun.COM 		return (FALSE);
13107917SReza.Sabdar@Sun.COM 
13117917SReza.Sabdar@Sun.COM 	(void) mutex_lock(&zlib_mtx);
13127917SReza.Sabdar@Sun.COM 	if (get_zfsvolname(vol, sizeof (vol), path) == -1) {
13137917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
13147917SReza.Sabdar@Sun.COM 		return (FALSE);
13157917SReza.Sabdar@Sun.COM 	}
13167917SReza.Sabdar@Sun.COM 
13177917SReza.Sabdar@Sun.COM 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
13187917SReza.Sabdar@Sun.COM 		(void) mutex_unlock(&zlib_mtx);
13197917SReza.Sabdar@Sun.COM 		return (FALSE);
13207917SReza.Sabdar@Sun.COM 	}
13217917SReza.Sabdar@Sun.COM 	zfs_close(zhp);
13227917SReza.Sabdar@Sun.COM 	(void) mutex_unlock(&zlib_mtx);
13237917SReza.Sabdar@Sun.COM 
13247917SReza.Sabdar@Sun.COM 	return (TRUE);
13257917SReza.Sabdar@Sun.COM }
13267917SReza.Sabdar@Sun.COM 
13277917SReza.Sabdar@Sun.COM /*
13287917SReza.Sabdar@Sun.COM  * Check if the volume is read-only
13297917SReza.Sabdar@Sun.COM  */
13307917SReza.Sabdar@Sun.COM boolean_t
fs_is_rdonly(char * path)13317917SReza.Sabdar@Sun.COM fs_is_rdonly(char *path)
13327917SReza.Sabdar@Sun.COM {
13337917SReza.Sabdar@Sun.COM 	return (fs_is_chkpntvol(path));
13347917SReza.Sabdar@Sun.COM }
13357917SReza.Sabdar@Sun.COM 
13367917SReza.Sabdar@Sun.COM /*
13377917SReza.Sabdar@Sun.COM  * Min/max functions
13387917SReza.Sabdar@Sun.COM  */
13397917SReza.Sabdar@Sun.COM unsigned
min(a,b)13407917SReza.Sabdar@Sun.COM min(a, b)
13417917SReza.Sabdar@Sun.COM 	unsigned a, b;
13427917SReza.Sabdar@Sun.COM {
13437917SReza.Sabdar@Sun.COM 	return (a < b ? a : b);
13447917SReza.Sabdar@Sun.COM }
13457917SReza.Sabdar@Sun.COM 
13467917SReza.Sabdar@Sun.COM unsigned
max(a,b)13477917SReza.Sabdar@Sun.COM max(a, b)
13487917SReza.Sabdar@Sun.COM 	unsigned a, b;
13497917SReza.Sabdar@Sun.COM {
13507917SReza.Sabdar@Sun.COM 	return (a > b ? a : b);
13517917SReza.Sabdar@Sun.COM }
13527917SReza.Sabdar@Sun.COM 
13537917SReza.Sabdar@Sun.COM longlong_t
llmin(longlong_t a,longlong_t b)13547917SReza.Sabdar@Sun.COM llmin(longlong_t a, longlong_t b)
13557917SReza.Sabdar@Sun.COM {
13567917SReza.Sabdar@Sun.COM 	return (a < b ? a : b);
13577917SReza.Sabdar@Sun.COM }
1358