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