xref: /illumos-gate/usr/src/cmd/ndmpd/tlm/tlm_lib.c (revision 4f364e7c95ee7fd9d5bbeddc1940e92405bb0e72)
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 <ndmpd_prop.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, "%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: Original path name.
714  *
715  * Output:
716  * 	name: Original name modified to include a snapshot.
717  *
718  * Returns:
719  * 	Original 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/%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 	char *drive_type;
1020 
1021 	/* Initialize the scsi adapter link */
1022 	sa->sa_link_head.sl_next = &sa->sa_link_head;
1023 
1024 	/* Scan for the changer */
1025 	dirp = opendir(SCSI_CHANGER_DIR);
1026 	if (dirp == NULL) {
1027 		NDMP_LOG(LOG_DEBUG,
1028 		    "Changer directory read error %s", SCSI_CHANGER_DIR);
1029 	} else {
1030 		while ((dp = readdir(dirp)) != NULL) {
1031 			if ((strcmp(dp->d_name, ".") == 0) ||
1032 			    (strcmp(dp->d_name, "..") == 0))
1033 				continue;
1034 
1035 			if ((p = strchr(dp->d_name, 'd')) != NULL) {
1036 				lun = atoi(++p);
1037 				p = strchr(dp->d_name, 't');
1038 				sid = atoi(++p);
1039 			}
1040 			else
1041 				sid = atoi(dp->d_name);
1042 
1043 			scsi_sasd_attach(sa, 0, lun, dp->d_name,
1044 			    DTYPE_CHANGER);
1045 		}
1046 		(void) closedir(dirp);
1047 	}
1048 
1049 	/* Scan for tape drives */
1050 	dirp = opendir(SCSI_TAPE_DIR);
1051 	if (dirp == NULL) {
1052 		NDMP_LOG(LOG_DEBUG,
1053 		    "Tape directory read error %s", SCSI_TAPE_DIR);
1054 	} else {
1055 		drive_type = ndmpd_get_prop(NDMP_DRIVE_TYPE);
1056 
1057 		if ((strcasecmp(drive_type, "sysv") != 0) &&
1058 		    (strcasecmp(drive_type, "bsd") != 0)) {
1059 			NDMP_LOG(LOG_ERR, "Invalid ndmpd/drive-type value. "
1060 			    "Valid values are 'sysv' and 'bsd'.");
1061 			return (-1);
1062 		}
1063 
1064 		while ((dp = readdir(dirp)) != NULL) {
1065 			if ((strcmp(dp->d_name, ".") == 0) ||
1066 			    (strcmp(dp->d_name, "..") == 0))
1067 				continue;
1068 
1069 			/* Skip special modes */
1070 			if (strpbrk(dp->d_name, "chlmu") != NULL)
1071 				continue;
1072 
1073 			/* Pick the non-rewind device */
1074 			if (strchr(dp->d_name, 'n') == NULL)
1075 				continue;
1076 
1077 			if (strcasecmp(drive_type, "sysv") == 0) {
1078 				if (strchr(dp->d_name, 'b') != NULL)
1079 					continue;
1080 			} else if (strcasecmp(drive_type, "bsd") == 0) {
1081 				if (strchr(dp->d_name, 'b') == NULL)
1082 					continue;
1083 			}
1084 
1085 			sid = atoi(dp->d_name);
1086 
1087 			/*
1088 			 * SCSI ID should match with the ID of the device
1089 			 * (will be checked by SCSI get elements page later)
1090 			 */
1091 			scsi_sasd_attach(sa, sid, 0, dp->d_name,
1092 			    DTYPE_SEQUENTIAL);
1093 		}
1094 		(void) closedir(dirp);
1095 	}
1096 
1097 	return (0);
1098 }
1099 
1100 /*
1101  * Get the SCSI device type (tape, robot)
1102  */
1103 /*ARGSUSED*/
1104 int
1105 scsi_get_devtype(char *adapter, int sid, int lun)
1106 {
1107 	int rv;
1108 	scsi_adapter_t *sa = &my_sa;
1109 	scsi_link_t *sl, *sh;
1110 
1111 	rv = -1;
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 			rv = sl->sl_type;
1116 
1117 	return (rv);
1118 }
1119 
1120 
1121 /*
1122  * Check if the SCSI device exists
1123  */
1124 /*ARGSUSED*/
1125 int
1126 scsi_dev_exists(char *adapter, int sid, int lun)
1127 {
1128 	scsi_adapter_t *sa = &my_sa;
1129 	scsi_link_t *sl, *sh;
1130 
1131 	sh = &sa->sa_link_head;
1132 	for (sl = sh->sl_next; sl != sh; sl = sl->sl_next)
1133 		if (sl->sl_sid == sid && sl->sl_lun == lun)
1134 			return (1);
1135 	return (0);
1136 }
1137 
1138 
1139 /*
1140  * Count of SCSI adapters
1141  */
1142 int
1143 scsi_get_adapter_count(void)
1144 {
1145 	/* Currently support one adapter only */
1146 	return (1);
1147 }
1148 
1149 /*
1150  * Return the SCSI adapter structure
1151  */
1152 /*ARGSUSED*/
1153 scsi_adapter_t *
1154 scsi_get_adapter(int adapter)
1155 {
1156 	return (&my_sa);
1157 }
1158 
1159 /*
1160  * IOCTL wrapper with retries
1161  */
1162 int
1163 tlm_ioctl(int fd, int cmd, void *data)
1164 {
1165 	int retries = 0;
1166 
1167 	NDMP_LOG(LOG_DEBUG, "tlm_ioctl fd %d cmd %d", fd, cmd);
1168 	if (fd == 0 || data == NULL)
1169 		return (EINVAL);
1170 
1171 	do {
1172 		if (ioctl(fd, cmd, data) == 0)
1173 			break;
1174 
1175 		if (errno != EIO && errno != 0) {
1176 			NDMP_LOG(LOG_ERR,
1177 			    "Failed to send command to device: %m.");
1178 			NDMP_LOG(LOG_DEBUG, "IOCTL error %d", errno);
1179 			return (errno);
1180 		}
1181 		(void) sleep(1);
1182 	} while (retries++ < MAXIORETRY);
1183 
1184 	return (0);
1185 }
1186 
1187 /*
1188  * Checkpoint or snapshot calls
1189  */
1190 
1191 /*
1192  * Get the snapshot creation time
1193  */
1194 int
1195 chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp)
1196 {
1197 	char chk_name[PATH_MAX];
1198 	zfs_handle_t *zhp;
1199 	char *p;
1200 
1201 	if (!volname || !*volname)
1202 		return (-1);
1203 
1204 	/* Should also return -1 if checkpoint not enabled */
1205 
1206 	/* Remove the leading slash */
1207 	p = volname;
1208 	while (*p == '/')
1209 		p++;
1210 
1211 	(void) strlcpy(chk_name, p, PATH_MAX);
1212 	(void) strlcat(chk_name, "@", PATH_MAX);
1213 	(void) strlcat(chk_name, pattern, PATH_MAX);
1214 
1215 	(void) mutex_lock(&zlib_mtx);
1216 	if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_DATASET)) == NULL) {
1217 		NDMP_LOG(LOG_DEBUG, "chkpnt_creationtime: open %s failed",
1218 		    chk_name);
1219 		(void) mutex_unlock(&zlib_mtx);
1220 		return (-1);
1221 	}
1222 
1223 	*tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
1224 	zfs_close(zhp);
1225 	(void) mutex_unlock(&zlib_mtx);
1226 
1227 	return (0);
1228 }
1229 
1230 
1231 /*
1232  * Get the ZFS volume name out of the given path
1233  */
1234 int
1235 get_zfsvolname(char *volname, int len, char *path)
1236 {
1237 	struct stat64 stbuf;
1238 	struct extmnttab ent;
1239 	FILE *mntfp;
1240 	int rv;
1241 
1242 	*volname = '\0';
1243 	if (stat64(path, &stbuf) != 0) {
1244 		return (-1);
1245 	}
1246 
1247 	if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
1248 		return (-1);
1249 	}
1250 	while ((rv = getextmntent(mntfp, &ent, 0)) == 0) {
1251 		if (makedevice(ent.mnt_major, ent.mnt_minor) ==
1252 		    stbuf.st_dev)
1253 			break;
1254 	}
1255 
1256 	if (rv == 0 &&
1257 	    strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0)
1258 		(void) strlcpy(volname, ent.mnt_special, len);
1259 	else
1260 		rv = -1;
1261 
1262 	(void) fclose(mntfp);
1263 	return (rv);
1264 }
1265 
1266 
1267 /*
1268  * Check if the volume type is snapshot volume
1269  */
1270 boolean_t
1271 fs_is_chkpntvol(char *path)
1272 {
1273 	zfs_handle_t *zhp;
1274 	char vol[ZFS_MAXNAMELEN];
1275 
1276 	if (!path || !*path)
1277 		return (FALSE);
1278 
1279 	if (get_zfsvolname(vol, sizeof (vol), path) == -1)
1280 		return (FALSE);
1281 
1282 	(void) mutex_lock(&zlib_mtx);
1283 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
1284 		(void) mutex_unlock(&zlib_mtx);
1285 		return (FALSE);
1286 	}
1287 
1288 	if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
1289 		zfs_close(zhp);
1290 		(void) mutex_unlock(&zlib_mtx);
1291 		return (FALSE);
1292 	}
1293 	zfs_close(zhp);
1294 	(void) mutex_unlock(&zlib_mtx);
1295 
1296 	return (TRUE);
1297 }
1298 
1299 /*
1300  * Check if the volume is capable of checkpoints
1301  */
1302 boolean_t
1303 fs_is_chkpnt_enabled(char *path)
1304 {
1305 	zfs_handle_t *zhp;
1306 	char vol[ZFS_MAXNAMELEN];
1307 
1308 	if (!path || !*path)
1309 		return (FALSE);
1310 
1311 	(void) mutex_lock(&zlib_mtx);
1312 	if (get_zfsvolname(vol, sizeof (vol), path) == -1) {
1313 		(void) mutex_unlock(&zlib_mtx);
1314 		return (FALSE);
1315 	}
1316 
1317 	if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
1318 		(void) mutex_unlock(&zlib_mtx);
1319 		return (FALSE);
1320 	}
1321 	zfs_close(zhp);
1322 	(void) mutex_unlock(&zlib_mtx);
1323 
1324 	return (TRUE);
1325 }
1326 
1327 /*
1328  * Check if the volume is read-only
1329  */
1330 boolean_t
1331 fs_is_rdonly(char *path)
1332 {
1333 	return (fs_is_chkpntvol(path));
1334 }
1335 
1336 /*
1337  * Min/max functions
1338  */
1339 unsigned
1340 min(a, b)
1341 	unsigned a, b;
1342 {
1343 	return (a < b ? a : b);
1344 }
1345 
1346 unsigned
1347 max(a, b)
1348 	unsigned a, b;
1349 {
1350 	return (a > b ? a : b);
1351 }
1352 
1353 longlong_t
1354 llmin(longlong_t a, longlong_t b)
1355 {
1356 	return (a < b ? a : b);
1357 }
1358