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