xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_lib.c (revision 98b45ebecf42e6d81a4aa85f88ffcc06af817f34)
1 /*
2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3  */
4 
5 /*
6  * BSD 3 Clause License
7  *
8  * Copyright (c) 2007, The Storage Networking Industry Association.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 	- Redistributions of source code must retain the above copyright
14  *	  notice, this list of conditions and the following disclaimer.
15  *
16  * 	- Redistributions in binary form must reproduce the above copyright
17  *	  notice, this list of conditions and the following disclaimer in
18  *	  the documentation and/or other materials provided with the
19  *	  distribution.
20  *
21  *	- Neither the name of The Storage Networking Industry Association (SNIA)
22  *	  nor the names of its contributors may be used to endorse or promote
23  *	  products derived from this software without specific prior written
24  *	  permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 #include <sys/errno.h>
39 #include <ctype.h>
40 #include <stdlib.h>
41 #include <time.h>
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <libzfs.h>
45 #include <pthread.h>
46 #include "tlm.h"
47 #include "tlm_proto.h"
48 #include <sys/mtio.h>
49 #include <sys/mnttab.h>
50 #include <sys/mntent.h>
51 #include <sys/statvfs.h>
52 #include <sys/scsi/impl/uscsi.h>
53 #include <sys/scsi/scsi.h>
54 #include <sys/mtio.h>
55 #include <thread.h>
56 #include <synch.h>
57 #include <sys/mutex.h>
58 #include <sys/sysmacros.h>
59 #include <sys/mkdev.h>
60 
61 /*
62  * Tar archiving ops vector
63  */
64 tm_ops_t tm_tar_ops = {
65 	"tar",
66 	tar_putfile,
67 	tar_putdir,
68 	NULL,
69 	tar_getfile,
70 	tar_getdir,
71 	NULL
72 };
73 
74 extern	libzfs_handle_t *zlibh;
75 extern	mutex_t zlib_mtx;
76 
77 /*
78  * get the next tape buffer from the drive's pool of buffers
79  */
80 /*ARGSUSED*/
81 char *
82 tlm_get_write_buffer(long want, long *actual_size,
83     tlm_buffers_t *buffers, int zero)
84 {
85 	int	buf = buffers->tbs_buffer_in;
86 	tlm_buffer_t *buffer = &buffers->tbs_buffer[buf];
87 	int	align_size = RECORDSIZE - 1;
88 	char	*rec;
89 
90 	/*
91 	 * make sure the allocation is in chunks of 512 bytes
92 	 */
93 	want += align_size;
94 	want &= ~align_size;
95 
96 	*actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
97 	if (*actual_size <= 0) {
98 		/*
99 		 * no room, send this one
100 		 * and wait for a free one
101 		 */
102 		if (!buffer->tb_full) {
103 			/*
104 			 * we are now ready to send a full buffer
105 			 * instead of trying to get a new buffer
106 			 *
107 			 * do not send if we failed to get a buffer
108 			 * on the previous call
109 			 */
110 			buffer->tb_full = TRUE;
111 
112 			/*
113 			 * tell the writer that a buffer is available
114 			 */
115 			tlm_buffer_release_in_buf(buffers);
116 
117 			buffer = tlm_buffer_advance_in_idx(buffers);
118 		}
119 
120 		buffer = tlm_buffer_in_buf(buffers, NULL);
121 
122 		if (buffer->tb_full) {
123 			/*
124 			 * wait for the writer to free up a buffer
125 			 */
126 			tlm_buffer_out_buf_timed_wait(buffers, 500);
127 		}
128 
129 		buffer = tlm_buffer_in_buf(buffers, NULL);
130 		if (buffer->tb_full) {
131 			/*
132 			 * the next buffer is still full
133 			 * of data from previous activity
134 			 *
135 			 * nothing has changed.
136 			 */
137 			return (0);
138 		}
139 
140 		buffer->tb_buffer_spot = 0;
141 		*actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
142 	}
143 
144 	*actual_size = min(want, *actual_size);
145 	rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot];
146 	buffer->tb_buffer_spot += *actual_size;
147 	buffers->tbs_offset += *actual_size;
148 	if (zero) {
149 		(void) memset(rec, 0, *actual_size);
150 	}
151 	return (rec);
152 }
153 
154 /*
155  * get a read record from the tape buffer,
156  * and read a tape block if necessary
157  */
158 /*ARGSUSED*/
159 char *
160 tlm_get_read_buffer(int want, int *error,
161     tlm_buffers_t *buffers, int *actual_size)
162 {
163 	tlm_buffer_t *buffer;
164 	int	align_size = RECORDSIZE - 1;
165 	int	buf;
166 	int	current_size;
167 	char	*rec;
168 
169 	buf = buffers->tbs_buffer_out;
170 	buffer = &buffers->tbs_buffer[buf];
171 
172 	/*
173 	 * make sure the allocation is in chunks of 512 bytes
174 	 */
175 	want += align_size;
176 	want &= ~align_size;
177 
178 	current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
179 	if (buffer->tb_full && current_size <= 0) {
180 		/*
181 		 * no more data, release this
182 		 * one and go get another
183 		 */
184 
185 		/*
186 		 * tell the reader that a buffer is available
187 		 */
188 		buffer->tb_full = FALSE;
189 		tlm_buffer_release_out_buf(buffers);
190 
191 		buffer = tlm_buffer_advance_out_idx(buffers);
192 		current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
193 	}
194 
195 	if (!buffer->tb_full) {
196 		/*
197 		 * next buffer is not full yet.
198 		 * wait for the reader.
199 		 */
200 		tlm_buffer_in_buf_timed_wait(buffers, 500);
201 
202 		buffer = tlm_buffer_out_buf(buffers, NULL);
203 		if (!buffer->tb_full) {
204 			/*
205 			 * we do not have anything from the tape yet
206 			 */
207 			return (0);
208 		}
209 
210 		current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
211 	}
212 
213 	/* Make sure we got something */
214 	if (current_size <= 0)
215 		return (NULL);
216 
217 	current_size = min(want, current_size);
218 	rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot];
219 	buffer->tb_buffer_spot += current_size;
220 	*actual_size = current_size;
221 
222 	/*
223 	 * the error flag is only sent back one time,
224 	 * since the flag refers to a previous read
225 	 * attempt, not the data in this buffer.
226 	 */
227 	*error = buffer->tb_errno;
228 
229 	return (rec);
230 }
231 
232 
233 /*
234  * unread a previously read buffer back to the tape buffer
235  */
236 void
237 tlm_unget_read_buffer(tlm_buffers_t *buffers, int size)
238 {
239 	tlm_buffer_t *buffer;
240 	int	align_size = RECORDSIZE - 1;
241 	int	buf;
242 	int	current_size;
243 
244 	buf = buffers->tbs_buffer_out;
245 	buffer = &buffers->tbs_buffer[buf];
246 
247 	/*
248 	 * make sure the allocation is in chunks of 512 bytes
249 	 */
250 	size += align_size;
251 	size &= ~align_size;
252 
253 	current_size = min(size, buffer->tb_buffer_spot);
254 	buffer->tb_buffer_spot -= current_size;
255 }
256 
257 
258 /*
259  * unwrite a previously written buffer
260  */
261 void
262 tlm_unget_write_buffer(tlm_buffers_t *buffers, int size)
263 {
264 	tlm_buffer_t *buffer;
265 	int	align_size = RECORDSIZE - 1;
266 	int	buf;
267 	int	current_size;
268 
269 	buf = buffers->tbs_buffer_in;
270 	buffer = &buffers->tbs_buffer[buf];
271 
272 	/*
273 	 * make sure the allocation is in chunks of 512 bytes
274 	 */
275 	size += align_size;
276 	size &= ~align_size;
277 
278 	current_size = min(size, buffer->tb_buffer_spot);
279 	buffer->tb_buffer_spot -= current_size;
280 }
281 
282 
283 /*
284  * build a checksum for a TAR header record
285  */
286 void
287 tlm_build_header_checksum(tlm_tar_hdr_t *r)
288 {
289 	int	i;
290 	int	sum = 0;
291 	char *c = (char *)r;
292 
293 	(void) memcpy(r->th_chksum, CHKBLANKS, strlen(CHKBLANKS));
294 	for (i = 0; i < RECORDSIZE; i++) {
295 		sum += c[i] & 0xFF;
296 	}
297 	(void) snprintf(r->th_chksum, sizeof (r->th_chksum), "%6o", sum);
298 }
299 
300 /*
301  * verify the tar header checksum
302  */
303 int
304 tlm_vfy_tar_checksum(tlm_tar_hdr_t *tar_hdr)
305 {
306 	int	chksum = oct_atoi(tar_hdr->th_chksum);
307 	uchar_t	*p = (uchar_t *)tar_hdr;
308 	int	sum = 0;	/* initial value of checksum */
309 	int	i;		/* loop counter */
310 
311 	/*
312 	 * compute the checksum
313 	 */
314 	for (i = 0; i < RECORDSIZE; i++) {
315 		sum += p[i] & 0xFF;
316 	}
317 
318 	if (sum == 0) {
319 		NDMP_LOG(LOG_DEBUG,
320 		    "should be %d, is 0", chksum);
321 		/* a zero record ==> end of tar file */
322 		return (0);
323 	}
324 
325 	/*
326 	 * subtract out the label's checksum values
327 	 * this lets us undo the old checksum "in-
328 	 * place", no need to swap blanks in and out
329 	 */
330 	for (i = 0; i < 8; i++) {
331 		sum -= 0xFF & tar_hdr->th_chksum[i];
332 	}
333 
334 	/*
335 	 * replace the old checksum field with blanks
336 	 */
337 	sum += ' ' * 8;
338 
339 	if (sum != chksum)
340 		NDMP_LOG(LOG_DEBUG,
341 		    "should be %d, is %d", chksum, sum);
342 
343 	return ((sum == chksum) ? 1 : -1);
344 }
345 
346 /*
347  * get internal scsi_sasd entry for this tape drive
348  */
349 int
350 tlm_get_scsi_sasd_entry(int lib, int drv)
351 {
352 	int entry;
353 	int i, n;
354 	scsi_link_t *sl;
355 	tlm_drive_t *dp;
356 
357 	entry = -1;
358 	dp = tlm_drive(lib, drv);
359 	if (!dp) {
360 		NDMP_LOG(LOG_DEBUG, "NULL dp for (%d.%d)", lib, drv);
361 	} else if (!dp->td_slink) {
362 		NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink for (%d.%d)", lib, drv);
363 	} else if (!dp->td_slink->sl_sa) {
364 		NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink->sl_sa for (%d.%d)",
365 		    lib, drv);
366 	} else {
367 		/* search through the SASD table */
368 		n = sasd_dev_count();
369 		for (i = 0; i < n; i++) {
370 			sl = sasd_dev_slink(i);
371 			if (!sl)
372 				continue;
373 
374 			if (dp->td_slink->sl_sa == sl->sl_sa &&
375 			    dp->td_scsi_id == sl->sl_sid &&
376 			    dp->td_lun == sl->sl_lun) {
377 				/* all 3 variables match */
378 				entry = i;
379 				break;
380 			}
381 		}
382 	}
383 
384 	return (entry);
385 }
386 
387 /*
388  * get the OS device name for this tape
389  */
390 char *
391 tlm_get_tape_name(int lib, int drv)
392 {
393 	int entry;
394 
395 	entry = tlm_get_scsi_sasd_entry(lib, drv);
396 	if (entry >= 0) {
397 		sasd_drive_t *sd;
398 
399 		if ((sd = sasd_drive(entry)) != 0)
400 			return (sd->sd_name);
401 	}
402 
403 	return ("");
404 }
405 
406 /*
407  * create the IPC area between the reader and writer
408  */
409 tlm_cmd_t *
410 tlm_create_reader_writer_ipc(boolean_t write, long data_transfer_size)
411 {
412 	tlm_cmd_t *cmd;
413 
414 	cmd = ndmp_malloc(sizeof (tlm_cmd_t));
415 	if (cmd == NULL)
416 		return (NULL);
417 
418 	cmd->tc_reader = TLM_BACKUP_RUN;
419 	cmd->tc_writer = TLM_BACKUP_RUN;
420 	cmd->tc_ref = 1;
421 
422 	cmd->tc_buffers = tlm_allocate_buffers(write, data_transfer_size);
423 	if (cmd->tc_buffers == NULL) {
424 		free(cmd);
425 		return (NULL);
426 	}
427 
428 	(void) mutex_init(&cmd->tc_mtx, 0, NULL);
429 	(void) cond_init(&cmd->tc_cv, 0, NULL);
430 
431 	return (cmd);
432 }
433 
434 /*
435  * release(destroy) the IPC between the reader and writer
436  */
437 void
438 tlm_release_reader_writer_ipc(tlm_cmd_t *cmd)
439 {
440 	if (--cmd->tc_ref <= 0) {
441 		(void) mutex_lock(&cmd->tc_mtx);
442 		tlm_release_buffers(cmd->tc_buffers);
443 		(void) cond_destroy(&cmd->tc_cv);
444 		(void) mutex_unlock(&cmd->tc_mtx);
445 		(void) mutex_destroy(&cmd->tc_mtx);
446 		free(cmd);
447 	}
448 }
449 
450 
451 /*
452  * NDMP support begins here.
453  */
454 
455 /*
456  * Initialize the file history callback functions
457  */
458 lbr_fhlog_call_backs_t *
459 lbrlog_callbacks_init(void *cookie, path_hist_func_t log_pname_func,
460     dir_hist_func_t log_dir_func, node_hist_func_t log_node_func)
461 {
462 	lbr_fhlog_call_backs_t *p;
463 
464 	p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t));
465 	if (p == NULL)
466 		return (NULL);
467 
468 	p->fh_cookie = cookie;
469 	p->fh_logpname = (func_t)log_pname_func;
470 	p->fh_log_dir = (func_t)log_dir_func;
471 	p->fh_log_node = (func_t)log_node_func;
472 	return (p);
473 }
474 
475 /*
476  * Cleanup the callbacks
477  */
478 void
479 lbrlog_callbacks_done(lbr_fhlog_call_backs_t *p)
480 {
481 	if (p != NULL)
482 		(void) free((char *)p);
483 }
484 
485 /*
486  * Call back for file history directory info
487  */
488 int
489 tlm_log_fhdir(tlm_job_stats_t *job_stats, char *dir, struct stat64 *stp,
490     fs_fhandle_t *fhp)
491 {
492 	int rv;
493 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
494 
495 	rv = 0;
496 	if (job_stats == NULL) {
497 		NDMP_LOG(LOG_DEBUG, "log_fhdir: jstat is NULL");
498 	} else if (dir == NULL) {
499 		NDMP_LOG(LOG_DEBUG, "log_fhdir: dir is NULL");
500 	} else if (stp == NULL) {
501 		NDMP_LOG(LOG_DEBUG, "log_fhdir: stp is NULL");
502 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
503 	    == NULL) {
504 		NDMP_LOG(LOG_DEBUG, "log_fhdir: cbp is NULL");
505 	} else if (cbp->fh_log_dir == NULL) {
506 		NDMP_LOG(LOG_DEBUG, "log_fhdir: callback is NULL");
507 	} else
508 		rv = (*cbp->fh_log_dir)(cbp, dir, stp, fhp);
509 
510 	return (rv);
511 }
512 
513 /*
514  * Call back for file history node info
515  */
516 int
517 tlm_log_fhnode(tlm_job_stats_t *job_stats, char *dir, char *file,
518     struct stat64 *stp, u_longlong_t off)
519 {
520 	int rv;
521 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
522 
523 	rv = 0;
524 	if (job_stats == NULL) {
525 		NDMP_LOG(LOG_DEBUG, "log_fhnode: jstat is NULL");
526 	} else if (dir == NULL) {
527 		NDMP_LOG(LOG_DEBUG, "log_fhnode: dir is NULL");
528 	} else if (file == NULL) {
529 		NDMP_LOG(LOG_DEBUG, "log_fhnode: file is NULL");
530 	} else if (stp == NULL) {
531 		NDMP_LOG(LOG_DEBUG, "log_fhnode: stp is NULL");
532 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
533 	    == NULL) {
534 		NDMP_LOG(LOG_DEBUG, "log_fhnode: cbp is NULL");
535 	} else if (cbp->fh_log_node == NULL) {
536 		NDMP_LOG(LOG_DEBUG, "log_fhnode: callback is NULL");
537 	} else
538 		rv = (*cbp->fh_log_node)(cbp, dir, file, stp, off);
539 
540 	return (rv);
541 }
542 
543 /*
544  * Call back for file history path info
545  */
546 int
547 tlm_log_fhpath_name(tlm_job_stats_t *job_stats, char *pathname,
548     struct stat64 *stp, u_longlong_t off)
549 {
550 	int rv;
551 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
552 
553 	rv = 0;
554 	if (!job_stats) {
555 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: jstat is NULL");
556 	} else if (!pathname) {
557 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: pathname is NULL");
558 	} else if (!stp) {
559 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: stp is NULL");
560 	} else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks)
561 	    == 0) {
562 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: cbp is NULL");
563 	} else if (!cbp->fh_logpname) {
564 		NDMP_LOG(LOG_DEBUG, "log_fhpath_name: callback is NULL");
565 	} else
566 		rv = (*cbp->fh_logpname)(cbp, pathname, stp, off);
567 
568 	return (rv);
569 }
570 
571 
572 /*
573  * Log call back to report the entry recovery
574  */
575 int
576 tlm_entry_restored(tlm_job_stats_t *job_stats, char *name, int pos)
577 {
578 	lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
579 
580 	NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d", name, pos);
581 
582 	if (job_stats == NULL) {
583 		NDMP_LOG(LOG_DEBUG, "entry_restored: jstat is NULL");
584 		return (0);
585 	}
586 	cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks;
587 	if (cbp == NULL) {
588 		NDMP_LOG(LOG_DEBUG, "entry_restored is NULL");
589 		return (0);
590 	}
591 	return (*cbp->fh_logpname)(cbp, name, 0, (longlong_t)pos);
592 }
593 /*
594  * NDMP support ends here.
595  */
596 
597 /*
598  * Function: tlm_cat_path
599  * Concatenates two path names
600  * or directory name and file name
601  * into a buffer passed by the caller. A slash
602  * is inserted if required. Buffer is assumed
603  * to hold PATH_MAX characters.
604  *
605  * Parameters:
606  *	char *buf	- buffer to write new dir/name string
607  *	char *dir	- directory name
608  *	char *name	- file name
609  *
610  * Returns:
611  *	TRUE		- No errors. buf contains the dir/name string
612  *	FALSE		- Error. buf is not modified.
613  */
614 boolean_t
615 tlm_cat_path(char *buf, char *dir, char *name)
616 {
617 	char *fmt;
618 	int dirlen = strlen(dir);
619 	int filelen = strlen(name);
620 
621 	if ((dirlen + filelen + 1) >= PATH_MAX) {
622 		return (FALSE);
623 	}
624 
625 	if (*dir == '\0' || *name == '\0' || dir[dirlen - 1] == '/' ||
626 	    *name == '/') {
627 		fmt = "%s%s";
628 	} else {
629 		fmt = "%s/%s";
630 	}
631 
632 	/* check for ".../" and "/...." */
633 	if ((dirlen > 0) && (dir[dirlen - 1] == '/') && (*name == '/'))
634 		name += strspn(name, "/");
635 
636 	/* LINTED variable format */
637 	(void) snprintf(buf, TLM_MAX_PATH_NAME, fmt, dir, name);
638 
639 	return (TRUE);
640 }
641 
642 /*
643  * Get the checkpoint (snapshot) creation time.
644  * This is necessary to check for checkpoints not being stale.
645  */
646 int
647 tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname)
648 {
649 	char volname[TLM_VOLNAME_MAX_LENGTH];
650 	char chk_name[PATH_MAX];
651 	char *cp_nm;
652 
653 	NDMP_LOG(LOG_DEBUG, "path [%s] auto_checkpoint: %d",
654 	    path, auto_checkpoint);
655 
656 	if (path == NULL || *path == '\0' || tp == NULL)
657 		return (-1);
658 
659 	if (get_zfsvolname(volname, TLM_VOLNAME_MAX_LENGTH,
660 	    path) == -1)
661 		return (-1);
662 
663 	if (auto_checkpoint) {
664 		NDMP_LOG(LOG_DEBUG, "volname [%s]", volname);
665 		(void) snprintf(chk_name, PATH_MAX, "%s", jname);
666 		return (chkpnt_creationtime_bypattern(volname, chk_name, tp));
667 	}
668 	cp_nm = strchr(volname, '@');
669 	NDMP_LOG(LOG_DEBUG, "volname [%s] cp_nm [%s]", volname, cp_nm);
670 
671 	return (chkpnt_creationtime_bypattern(volname, cp_nm, tp));
672 }
673 
674 /*
675  * Release an array of pointers and the pointers themselves.
676  */
677 void
678 tlm_release_list(char **lpp)
679 {
680 	char **save;
681 
682 	if ((save = lpp) == 0)
683 		return;
684 
685 	while (*lpp)
686 		free(*lpp++);
687 
688 	free(save);
689 }
690 
691 /*
692  * Print the list of array of strings in the backup log
693  */
694 void
695 tlm_log_list(char *title, char **lpp)
696 {
697 	int i;
698 
699 	if (!lpp)
700 		return;
701 
702 	NDMP_LOG(LOG_DEBUG, "%s:", title);
703 
704 	for (i = 0; *lpp; lpp++, i++)
705 		NDMP_LOG(LOG_DEBUG, "%d: [%s]", i, *lpp);
706 }
707 
708 /*
709  * Insert the backup snapshot name into the path.
710  *
711  * Input:
712  * 	name: Original path name.
713  *
714  * Output:
715  * 	name: Original name modified to include a snapshot.
716  *
717  * Returns:
718  * 	Original name modified to include a snapshot.
719  */
720 char *
721 tlm_build_snapshot_name(char *name, char *sname, char *jname)
722 {
723 	zfs_handle_t *zhp;
724 	char *rest;
725 	char volname[ZFS_MAXNAMELEN];
726 	char mountpoint[PATH_MAX];
727 
728 	if (get_zfsvolname(volname, ZFS_MAXNAMELEN, name) == -1)
729 		goto notzfs;
730 
731 	(void) mutex_lock(&zlib_mtx);
732 	if ((zlibh == NULL) ||
733 	    (zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == NULL) {
734 		(void) mutex_unlock(&zlib_mtx);
735 		goto notzfs;
736 	}
737 
738 	if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, PATH_MAX, NULL,
739 	    NULL, 0, B_FALSE) != 0) {
740 		zfs_close(zhp);
741 		(void) mutex_unlock(&zlib_mtx);
742 		goto notzfs;
743 	}
744 
745 	zfs_close(zhp);
746 	(void) mutex_unlock(&zlib_mtx);
747 
748 	rest = name + strlen(mountpoint);
749 	(void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint,
750 	    TLM_SNAPSHOT_DIR, jname, rest);
751 
752 	return (sname);
753 
754 notzfs:
755 	(void) strlcpy(sname, name, TLM_MAX_PATH_NAME);
756 	return (sname);
757 }
758 
759 /*
760  * Remove the checkpoint from a path name.
761  *
762  * Input:
763  * 	name: Full pathname with checkpoint embeded.
764  *
765  * Output:
766  * 	unchkp_name: real pathname with no checkpoint.
767  *
768  * Returns:
769  *	Pointer to the un-checkpointed path.
770  */
771 char *
772 tlm_remove_checkpoint(char *name, char *unchkp_name)
773 {
774 	char *cp;
775 	int i;
776 	int plen;
777 
778 	unchkp_name[0] = name[0];
779 	plen = strlen(TLM_SNAPSHOT_PREFIX);
780 	for (i = 1; i <= TLM_VOLNAME_MAX_LENGTH + 1; i++) {
781 		switch (name[i]) {
782 		case '.':
783 			if (strncmp(&name[i], TLM_SNAPSHOT_PREFIX,
784 			    plen) == 0) {
785 				unchkp_name[i] = '\0';
786 				i += plen;
787 				if (name[i] == '\0') {
788 					/*
789 					 * name == "/v1.chkpnt"
790 					 */
791 					return (unchkp_name);
792 				}
793 				if ((cp = strchr(&name[++i], '/')) != NULL) {
794 					(void) strlcat(unchkp_name, cp,
795 					    TLM_VOLNAME_MAX_LENGTH + 1);
796 				}
797 				return (unchkp_name);
798 			} else {
799 				unchkp_name[i] = name[i];
800 			}
801 			break;
802 		case '/':
803 			return (name);
804 		case 0:
805 			return (name);
806 		default:
807 			unchkp_name[i] = name[i];
808 			break;
809 		}
810 	}
811 	return (name);
812 }
813 
814 /*
815  * see if we should exclude this file.
816  */
817 boolean_t
818 tlm_is_excluded(char *dir, char *name, char **excl_files)
819 {
820 	int	i;
821 	char	full_name[TLM_MAX_PATH_NAME];
822 
823 	if (!dir || !name || !excl_files)
824 		return (FALSE);
825 
826 	if (!tlm_cat_path(full_name, dir, name)) {
827 		NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]",
828 		    dir, name);
829 		return (FALSE);
830 	}
831 	for (i = 0; excl_files[i] != 0; i++) {
832 		if (match(excl_files[i], full_name)) {
833 			return (TRUE);
834 		}
835 	}
836 	return (FALSE);
837 }
838 
839 /*
840  * Check if the path is too long
841  */
842 boolean_t
843 tlm_is_too_long(int checkpointed, char *dir, char *nm)
844 {
845 	int nlen, tot;
846 
847 	tot = 0;
848 	if (dir)
849 		tot += strlen(dir);
850 	if (checkpointed)
851 		tot += strlen(TLM_SNAPSHOT_DIR) + 1;
852 	if (nm) {
853 		if ((nlen = strlen(nm)) > 0)
854 			tot += nlen + 1;
855 	}
856 	return ((tot >= PATH_MAX) ? TRUE : FALSE);
857 }
858 
859 /*
860  * Get the data offset of inside the buffer
861  */
862 longlong_t
863 tlm_get_data_offset(tlm_cmd_t *lcmds)
864 {
865 	if (!lcmds)
866 		return (0LL);
867 
868 	return (lcmds->tc_buffers->tbs_offset);
869 }
870 
871 /*
872  * Enable the barcode capability on the library
873  */
874 void
875 tlm_enable_barcode(int l)
876 {
877 	tlm_library_t *lp;
878 
879 	if ((lp = tlm_library(l))) {
880 		lp->tl_capability_barcodes = TRUE;
881 		NDMP_LOG(LOG_DEBUG,
882 		    "Barcode capability on library %d enabled.", l);
883 	}
884 }
885 
886 /*
887  * SASD SCSI support
888  */
889 static scsi_adapter_t my_sa;
890 static int sasd_drive_count = 0;
891 static scsi_sasd_drive_t *scsi_sasd_drives[128];
892 
893 /*
894  * Count of SCSI devices
895  */
896 int
897 sasd_dev_count(void)
898 {
899 	return (sasd_drive_count);
900 }
901 
902 /*
903  * Return the SCSI device name
904  */
905 char *
906 sasd_slink_name(scsi_link_t *slink)
907 {
908 	int i;
909 
910 	for (i = 0; i < sasd_drive_count; i++) {
911 		if (&scsi_sasd_drives[i]->ss_slink == slink)
912 			return (scsi_sasd_drives[i]->ss_sd.sd_name);
913 	}
914 	return (NULL);
915 }
916 
917 /*
918  * Return the SCSI drive structure
919  */
920 sasd_drive_t *
921 sasd_slink_drive(scsi_link_t *slink)
922 {
923 	int i;
924 
925 	for (i = 0; i < sasd_drive_count; i++) {
926 		if (&scsi_sasd_drives[i]->ss_slink == slink)
927 			return (&scsi_sasd_drives[i]->ss_sd);
928 	}
929 	return (NULL);
930 }
931 
932 /*
933  * Return the SCSI link pointer for the given index
934  */
935 scsi_link_t *
936 sasd_dev_slink(int entry)
937 {
938 	scsi_link_t *rv;
939 
940 	if (entry >= 0 && entry < sasd_drive_count)
941 		rv = &scsi_sasd_drives[entry]->ss_slink;
942 	else
943 		rv = NULL;
944 
945 	return (rv);
946 }
947 
948 /*
949  * Return the SCSI drive for the given index
950  */
951 sasd_drive_t *
952 sasd_drive(int entry)
953 {
954 	sasd_drive_t *rv;
955 
956 	if (entry >= 0 && entry < sasd_drive_count)
957 		rv = &scsi_sasd_drives[entry]->ss_sd;
958 	else
959 		rv = NULL;
960 
961 	return (rv);
962 }
963 
964 /*
965  * Attach the SCSI device by updating the structures
966  */
967 void
968 scsi_sasd_attach(scsi_adapter_t *sa, int sid, int lun, char *name,
969     int type)
970 {
971 	scsi_link_t *sl, *next;
972 	scsi_sasd_drive_t *ssd;
973 
974 	ssd = ndmp_malloc(sizeof (scsi_sasd_drive_t));
975 	if (ssd == NULL)
976 		return;
977 
978 	scsi_sasd_drives[sasd_drive_count++] = ssd;
979 
980 	switch (type) {
981 	case DTYPE_CHANGER:
982 		(void) snprintf(ssd->ss_sd.sd_name,
983 		    sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_CHANGER_DIR,
984 		    name);
985 		break;
986 	case DTYPE_SEQUENTIAL:
987 		(void) snprintf(ssd->ss_sd.sd_name,
988 		    sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_TAPE_DIR, name);
989 		break;
990 	}
991 
992 	sl = &ssd->ss_slink;
993 	sl->sl_type = type;
994 	sl->sl_sa = sa;
995 	sl->sl_lun = lun;
996 	sl->sl_sid = sid;
997 	sl->sl_requested_max_active = 1;
998 
999 	/* Insert slink */
1000 	next = sa->sa_link_head.sl_next;
1001 	sa->sa_link_head.sl_next = sl;
1002 	sl->sl_next = next;
1003 }
1004 
1005 /*
1006  * Go through the attached devices and detect the tape
1007  * and robot by checking the /dev entries
1008  */
1009 int
1010 probe_scsi(void)
1011 {
1012 	DIR *dirp;
1013 	struct dirent *dp;
1014 	scsi_adapter_t *sa = &my_sa;
1015 	char *p;
1016 	int lun = 0;
1017 	int sid = 0;
1018 
1019 	/* Initialize the scsi adapter link */
1020 	sa->sa_link_head.sl_next = &sa->sa_link_head;
1021 
1022 	/* Scan for the changer */
1023 	dirp = opendir(SCSI_CHANGER_DIR);
1024 	if (dirp == NULL) {
1025 		NDMP_LOG(LOG_DEBUG,
1026 		    "Changer directory read error %s", SCSI_CHANGER_DIR);
1027 	} else {
1028 		while ((dp = readdir(dirp)) != NULL) {
1029 			if ((strcmp(dp->d_name, ".") == 0) ||
1030 			    (strcmp(dp->d_name, "..") == 0))
1031 				continue;
1032 
1033 			if ((p = strchr(dp->d_name, 'd')) != NULL) {
1034 				lun = atoi(++p);
1035 				p = strchr(dp->d_name, 't');
1036 				sid = atoi(++p);
1037 			}
1038 			else
1039 				sid = atoi(dp->d_name);
1040 
1041 			scsi_sasd_attach(sa, 0, lun, dp->d_name,
1042 			    DTYPE_CHANGER);
1043 		}
1044 		(void) closedir(dirp);
1045 	}
1046 
1047 	/* Scan for tape drives */
1048 	dirp = opendir(SCSI_TAPE_DIR);
1049 	if (dirp == NULL) {
1050 		NDMP_LOG(LOG_DEBUG,
1051 		    "Tape directory read error %s", SCSI_TAPE_DIR);
1052 	} else {
1053 		while ((dp = readdir(dirp)) != NULL) {
1054 			if ((strcmp(dp->d_name, ".") == 0) ||
1055 			    (strcmp(dp->d_name, "..") == 0))
1056 				continue;
1057 
1058 			/* Skip special modes */
1059 			if (strpbrk(dp->d_name, "bchlmu") != 0)
1060 				continue;
1061 
1062 			/* Pick the non-rewind device */
1063 			if (strchr(dp->d_name, 'n') == NULL)
1064 				continue;
1065 
1066 			sid = atoi(dp->d_name);
1067 
1068 			/*
1069 			 * SCSI ID should match with the ID of the device
1070 			 * (will be checked by SCSI get elements page later)
1071 			 */
1072 			scsi_sasd_attach(sa, sid, 0, dp->d_name,
1073 			    DTYPE_SEQUENTIAL);
1074 		}
1075 		(void) closedir(dirp);
1076 	}
1077 
1078 	return (0);
1079 }
1080 
1081 /*
1082  * Get the SCSI device type (tape, robot)
1083  */
1084 /*ARGSUSED*/
1085 int
1086 scsi_get_devtype(char *adapter, int sid, int lun)
1087 {
1088 	int rv;
1089 	scsi_adapter_t *sa = &my_sa;
1090 	scsi_link_t *sl, *sh;
1091 
1092 	rv = -1;
1093 	sh = &sa->sa_link_head;
1094 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
1095 		if (sl->sl_sid == sid && sl->sl_lun == lun)
1096 			rv = sl->sl_type;
1097 
1098 	return (rv);
1099 }
1100 
1101 
1102 /*
1103  * Check if the SCSI device exists
1104  */
1105 /*ARGSUSED*/
1106 int
1107 scsi_dev_exists(char *adapter, int sid, int lun)
1108 {
1109 	scsi_adapter_t *sa = &my_sa;
1110 	scsi_link_t *sl, *sh;
1111 
1112 	sh = &sa->sa_link_head;
1113 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
1114 		if (sl->sl_sid == sid && sl->sl_lun == lun)
1115 			return (1);
1116 	return (0);
1117 }
1118 
1119 
1120 /*
1121  * Count of SCSI adapters
1122  */
1123 int
1124 scsi_get_adapter_count(void)
1125 {
1126 	/* Currently support one adapter only */
1127 	return (1);
1128 }
1129 
1130 /*
1131  * Return the SCSI adapter structure
1132  */
1133 /*ARGSUSED*/
1134 scsi_adapter_t *
1135 scsi_get_adapter(int adapter)
1136 {
1137 	return (&my_sa);
1138 }
1139 
1140 /*
1141  * IOCTL wrapper with retries
1142  */
1143 int
1144 tlm_ioctl(int fd, int cmd, void *data)
1145 {
1146 	int retries = 0;
1147 
1148 	NDMP_LOG(LOG_DEBUG, "tlm_ioctl fd %d cmd %d", fd, cmd);
1149 	if (fd == 0 || data == NULL)
1150 		return (EINVAL);
1151 
1152 	do {
1153 		if (ioctl(fd, cmd, data) == 0)
1154 			break;
1155 
1156 		if (errno != EIO && errno != 0) {
1157 			NDMP_LOG(LOG_ERR,
1158 			    "Failed to send command to device: %m.");
1159 			NDMP_LOG(LOG_DEBUG, "IOCTL error %d", errno);
1160 			return (errno);
1161 		}
1162 		(void) sleep(1);
1163 	} while (retries++ < MAXIORETRY);
1164 
1165 	return (0);
1166 }
1167 
1168 /*
1169  * Checkpoint or snapshot calls
1170  */
1171 
1172 /*
1173  * Get the snapshot creation time
1174  */
1175 int
1176 chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp)
1177 {
1178 	char chk_name[PATH_MAX];
1179 	zfs_handle_t *zhp;
1180 	char *p;
1181 
1182 	if (!volname || !*volname)
1183 		return (-1);
1184 
1185 	/* Should also return -1 if checkpoint not enabled */
1186 
1187 	/* Remove the leading slash */
1188 	p = volname;
1189 	while (*p == '/')
1190 		p++;
1191 
1192 	(void) strlcpy(chk_name, p, PATH_MAX);
1193 	(void) strlcat(chk_name, "@", PATH_MAX);
1194 	(void) strlcat(chk_name, pattern, PATH_MAX);
1195 
1196 	(void) mutex_lock(&zlib_mtx);
1197 	if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_DATASET)) == NULL) {
1198 		NDMP_LOG(LOG_DEBUG, "chkpnt_creationtime: open %s failed",
1199 		    chk_name);
1200 		(void) mutex_unlock(&zlib_mtx);
1201 		return (-1);
1202 	}
1203 
1204 	*tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
1205 	zfs_close(zhp);
1206 	(void) mutex_unlock(&zlib_mtx);
1207 
1208 	return (0);
1209 }
1210 
1211 
1212 /*
1213  * Get the ZFS volume name out of the given path
1214  */
1215 int
1216 get_zfsvolname(char *volname, int len, char *path)
1217 {
1218 	struct stat64 stbuf;
1219 	struct extmnttab ent;
1220 	FILE *mntfp;
1221 	int rv;
1222 
1223 	*volname = '\0';
1224 	if (stat64(path, &stbuf) != 0) {
1225 		return (-1);
1226 	}
1227 
1228 	if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
1229 		return (-1);
1230 	}
1231 	while ((rv = getextmntent(mntfp, &ent, 0)) == 0) {
1232 		if (makedevice(ent.mnt_major, ent.mnt_minor) ==
1233 		    stbuf.st_dev)
1234 			break;
1235 	}
1236 
1237 	if (rv == 0 &&
1238 	    strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0)
1239 		(void) strlcpy(volname, ent.mnt_special, len);
1240 	else
1241 		rv = -1;
1242 
1243 	(void) fclose(mntfp);
1244 	return (rv);
1245 }
1246 
1247 
1248 /*
1249  * Check if the volume type is snapshot volume
1250  */
1251 boolean_t
1252 fs_is_chkpntvol(char *path)
1253 {
1254 	zfs_handle_t *zhp;
1255 	char vol[ZFS_MAXNAMELEN];
1256 
1257 	if (!path || !*path)
1258 		return (FALSE);
1259 
1260 	if (get_zfsvolname(vol, sizeof (vol), path) == -1)
1261 		return (FALSE);
1262 
1263 	(void) mutex_lock(&zlib_mtx);
1264 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
1265 		(void) mutex_unlock(&zlib_mtx);
1266 		return (FALSE);
1267 	}
1268 
1269 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
1270 		zfs_close(zhp);
1271 		(void) mutex_unlock(&zlib_mtx);
1272 		return (FALSE);
1273 	}
1274 	zfs_close(zhp);
1275 	(void) mutex_unlock(&zlib_mtx);
1276 
1277 	return (TRUE);
1278 }
1279 
1280 /*
1281  * Check if the volume is capable of checkpoints
1282  */
1283 boolean_t
1284 fs_is_chkpnt_enabled(char *path)
1285 {
1286 	zfs_handle_t *zhp;
1287 	char vol[ZFS_MAXNAMELEN];
1288 
1289 	if (!path || !*path)
1290 		return (FALSE);
1291 
1292 	(void) mutex_lock(&zlib_mtx);
1293 	if (get_zfsvolname(vol, sizeof (vol), path) == -1) {
1294 		(void) mutex_unlock(&zlib_mtx);
1295 		return (FALSE);
1296 	}
1297 
1298 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
1299 		(void) mutex_unlock(&zlib_mtx);
1300 		return (FALSE);
1301 	}
1302 	zfs_close(zhp);
1303 	(void) mutex_unlock(&zlib_mtx);
1304 
1305 	return (TRUE);
1306 }
1307 
1308 /*
1309  * Check if the volume is read-only
1310  */
1311 boolean_t
1312 fs_is_rdonly(char *path)
1313 {
1314 	return (fs_is_chkpntvol(path));
1315 }
1316 
1317 /*
1318  * Min/max functions
1319  */
1320 unsigned
1321 min(a, b)
1322 	unsigned a, b;
1323 {
1324 	return (a < b ? a : b);
1325 }
1326 
1327 unsigned
1328 max(a, b)
1329 	unsigned a, b;
1330 {
1331 	return (a > b ? a : b);
1332 }
1333 
1334 longlong_t
1335 llmin(longlong_t a, longlong_t b)
1336 {
1337 	return (a < b ? a : b);
1338 }
1339