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