dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / ndmpd / tlm / tlm_lib.c
blob666ea3feca193f0661e2a2e1b33fde083738b3ce
1 /*
2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2015 by Delphix. All rights reserved.
4 */
6 /*
7 * BSD 3 Clause License
9 * Copyright (c) 2007, The Storage Networking Industry Association.
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.
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.
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.
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.
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>
64 * Tar archiving ops vector
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
76 extern libzfs_handle_t *zlibh;
77 extern mutex_t zlib_mtx;
80 * get the next tape buffer from the drive's pool of buffers
82 /*ARGSUSED*/
83 char *
84 tlm_get_write_buffer(long want, long *actual_size,
85 tlm_buffers_t *buffers, int zero)
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;
93 * make sure the allocation is in chunks of 512 bytes
95 want += align_size;
96 want &= ~align_size;
98 *actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
99 if (*actual_size <= 0) {
101 * no room, send this one
102 * and wait for a free one
104 if (!buffer->tb_full) {
106 * we are now ready to send a full buffer
107 * instead of trying to get a new buffer
109 * do not send if we failed to get a buffer
110 * on the previous call
112 buffer->tb_full = TRUE;
115 * tell the writer that a buffer is available
117 tlm_buffer_release_in_buf(buffers);
119 buffer = tlm_buffer_advance_in_idx(buffers);
122 buffer = tlm_buffer_in_buf(buffers, NULL);
124 if (buffer->tb_full) {
126 * wait for the writer to free up a buffer
128 tlm_buffer_out_buf_timed_wait(buffers, 500);
131 buffer = tlm_buffer_in_buf(buffers, NULL);
132 if (buffer->tb_full) {
134 * the next buffer is still full
135 * of data from previous activity
137 * nothing has changed.
139 return (0);
142 buffer->tb_buffer_spot = 0;
143 *actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
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);
153 return (rec);
157 * get a read record from the tape buffer,
158 * and read a tape block if necessary
160 /*ARGSUSED*/
161 char *
162 tlm_get_read_buffer(int want, int *error,
163 tlm_buffers_t *buffers, int *actual_size)
165 tlm_buffer_t *buffer;
166 int align_size = RECORDSIZE - 1;
167 int buf;
168 int current_size;
169 char *rec;
171 buf = buffers->tbs_buffer_out;
172 buffer = &buffers->tbs_buffer[buf];
175 * make sure the allocation is in chunks of 512 bytes
177 want += align_size;
178 want &= ~align_size;
180 current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
181 if (buffer->tb_full && current_size <= 0) {
183 * no more data, release this
184 * one and go get another
188 * tell the reader that a buffer is available
190 buffer->tb_full = FALSE;
191 tlm_buffer_release_out_buf(buffers);
193 buffer = tlm_buffer_advance_out_idx(buffers);
194 current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
197 if (!buffer->tb_full) {
199 * next buffer is not full yet.
200 * wait for the reader.
202 tlm_buffer_in_buf_timed_wait(buffers, 500);
204 buffer = tlm_buffer_out_buf(buffers, NULL);
205 if (!buffer->tb_full) {
207 * we do not have anything from the tape yet
209 return (0);
212 current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot;
215 /* Make sure we got something */
216 if (current_size <= 0)
217 return (NULL);
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;
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.
229 *error = buffer->tb_errno;
231 return (rec);
236 * unread a previously read buffer back to the tape buffer
238 void
239 tlm_unget_read_buffer(tlm_buffers_t *buffers, int size)
241 tlm_buffer_t *buffer;
242 int align_size = RECORDSIZE - 1;
243 int buf;
244 int current_size;
246 buf = buffers->tbs_buffer_out;
247 buffer = &buffers->tbs_buffer[buf];
250 * make sure the allocation is in chunks of 512 bytes
252 size += align_size;
253 size &= ~align_size;
255 current_size = min(size, buffer->tb_buffer_spot);
256 buffer->tb_buffer_spot -= current_size;
261 * unwrite a previously written buffer
263 void
264 tlm_unget_write_buffer(tlm_buffers_t *buffers, int size)
266 tlm_buffer_t *buffer;
267 int align_size = RECORDSIZE - 1;
268 int buf;
269 int current_size;
271 buf = buffers->tbs_buffer_in;
272 buffer = &buffers->tbs_buffer[buf];
275 * make sure the allocation is in chunks of 512 bytes
277 size += align_size;
278 size &= ~align_size;
280 current_size = min(size, buffer->tb_buffer_spot);
281 buffer->tb_buffer_spot -= current_size;
286 * build a checksum for a TAR header record
288 void
289 tlm_build_header_checksum(tlm_tar_hdr_t *r)
291 int i;
292 int sum = 0;
293 char *c = (char *)r;
295 (void) memcpy(r->th_chksum, CHKBLANKS, strlen(CHKBLANKS));
296 for (i = 0; i < RECORDSIZE; i++) {
297 sum += c[i] & 0xFF;
299 (void) snprintf(r->th_chksum, sizeof (r->th_chksum), "%6o", sum);
303 * verify the tar header checksum
306 tlm_vfy_tar_checksum(tlm_tar_hdr_t *tar_hdr)
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 */
314 * compute the checksum
316 for (i = 0; i < RECORDSIZE; i++) {
317 sum += p[i] & 0xFF;
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);
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
332 for (i = 0; i < 8; i++) {
333 sum -= 0xFF & tar_hdr->th_chksum[i];
337 * replace the old checksum field with blanks
339 sum += ' ' * 8;
341 if (sum != chksum)
342 NDMP_LOG(LOG_DEBUG,
343 "should be %d, is %d", chksum, sum);
345 return ((sum == chksum) ? 1 : -1);
349 * get internal scsi_sasd entry for this tape drive
352 tlm_get_scsi_sasd_entry(int lib, int drv)
354 int entry;
355 int i, n;
356 scsi_link_t *sl;
357 tlm_drive_t *dp;
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;
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;
386 return (entry);
390 * get the OS device name for this tape
392 char *
393 tlm_get_tape_name(int lib, int drv)
395 int entry;
397 entry = tlm_get_scsi_sasd_entry(lib, drv);
398 if (entry >= 0) {
399 sasd_drive_t *sd;
401 if ((sd = sasd_drive(entry)) != 0)
402 return (sd->sd_name);
405 return ("");
409 * create the IPC area between the reader and writer
411 tlm_cmd_t *
412 tlm_create_reader_writer_ipc(boolean_t write, long data_transfer_size)
414 tlm_cmd_t *cmd;
416 cmd = ndmp_malloc(sizeof (tlm_cmd_t));
417 if (cmd == NULL)
418 return (NULL);
420 cmd->tc_reader = TLM_BACKUP_RUN;
421 cmd->tc_writer = TLM_BACKUP_RUN;
422 cmd->tc_ref = 1;
424 cmd->tc_buffers = tlm_allocate_buffers(write, data_transfer_size);
425 if (cmd->tc_buffers == NULL) {
426 free(cmd);
427 return (NULL);
430 (void) mutex_init(&cmd->tc_mtx, 0, NULL);
431 (void) cond_init(&cmd->tc_cv, 0, NULL);
433 return (cmd);
437 * release(destroy) the IPC between the reader and writer
439 void
440 tlm_release_reader_writer_ipc(tlm_cmd_t *cmd)
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);
454 * NDMP support begins here.
458 * Initialize the file history callback functions
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)
464 lbr_fhlog_call_backs_t *p;
466 p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t));
467 if (p == NULL)
468 return (NULL);
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);
478 * Cleanup the callbacks
480 void
481 lbrlog_callbacks_done(lbr_fhlog_call_backs_t *p)
483 if (p != NULL)
484 (void) free((char *)p);
488 * Call back for file history directory info
491 tlm_log_fhdir(tlm_job_stats_t *job_stats, char *dir, struct stat64 *stp,
492 fs_fhandle_t *fhp)
494 int rv;
495 lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
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);
512 return (rv);
516 * Call back for file history node info
519 tlm_log_fhnode(tlm_job_stats_t *job_stats, char *dir, char *file,
520 struct stat64 *stp, u_longlong_t off)
522 int rv;
523 lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
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);
542 return (rv);
546 * Call back for file history path info
549 tlm_log_fhpath_name(tlm_job_stats_t *job_stats, char *pathname,
550 struct stat64 *stp, u_longlong_t off)
552 int rv;
553 lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
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);
570 return (rv);
575 * Log call back to report the entry recovery
578 tlm_entry_restored(tlm_job_stats_t *job_stats, char *name, int pos)
580 lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */
582 NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d", name, pos);
584 if (job_stats == NULL) {
585 NDMP_LOG(LOG_DEBUG, "entry_restored: jstat is NULL");
586 return (0);
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);
593 return (*cbp->fh_logpname)(cbp, name, 0, (longlong_t)pos);
596 * NDMP support ends here.
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.
607 * Parameters:
608 * char *buf - buffer to write new dir/name string
609 * char *dir - directory name
610 * char *name - file name
612 * Returns:
613 * TRUE - No errors. buf contains the dir/name string
614 * FALSE - Error. buf is not modified.
616 boolean_t
617 tlm_cat_path(char *buf, char *dir, char *name)
619 char *fmt;
620 int dirlen = strlen(dir);
621 int filelen = strlen(name);
623 if ((dirlen + filelen + 1) >= PATH_MAX) {
624 return (FALSE);
627 if (*dir == '\0' || *name == '\0' || dir[dirlen - 1] == '/' ||
628 *name == '/') {
629 fmt = "%s%s";
630 } else {
631 fmt = "%s/%s";
634 /* check for ".../" and "/...." */
635 if ((dirlen > 0) && (dir[dirlen - 1] == '/') && (*name == '/'))
636 name += strspn(name, "/");
638 /* LINTED variable format */
639 (void) snprintf(buf, TLM_MAX_PATH_NAME, fmt, dir, name);
641 return (TRUE);
645 * Get the checkpoint (snapshot) creation time.
646 * This is necessary to check for checkpoints not being stale.
649 tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname)
651 char volname[TLM_VOLNAME_MAX_LENGTH];
652 char chk_name[PATH_MAX];
653 char *cp_nm;
655 NDMP_LOG(LOG_DEBUG, "path [%s] auto_checkpoint: %d",
656 path, auto_checkpoint);
658 if (path == NULL || *path == '\0' || tp == NULL)
659 return (-1);
661 if (get_zfsvolname(volname, TLM_VOLNAME_MAX_LENGTH,
662 path) == -1)
663 return (-1);
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));
670 cp_nm = strchr(volname, '@');
671 NDMP_LOG(LOG_DEBUG, "volname [%s] cp_nm [%s]", volname, cp_nm);
673 return (chkpnt_creationtime_bypattern(volname, cp_nm, tp));
677 * Release an array of pointers and the pointers themselves.
679 void
680 tlm_release_list(char **lpp)
682 char **save;
684 if ((save = lpp) == 0)
685 return;
687 while (*lpp)
688 free(*lpp++);
690 free(save);
694 * Print the list of array of strings in the backup log
696 void
697 tlm_log_list(char *title, char **lpp)
699 int i;
701 if (!lpp)
702 return;
704 NDMP_LOG(LOG_DEBUG, "%s:", title);
706 for (i = 0; *lpp; lpp++, i++)
707 NDMP_LOG(LOG_DEBUG, "%d: [%s]", i, *lpp);
711 * Insert the backup snapshot name into the path.
713 * Input:
714 * name: Original path name.
716 * Output:
717 * name: Original name modified to include a snapshot.
719 * Returns:
720 * Original name modified to include a snapshot.
722 char *
723 tlm_build_snapshot_name(char *name, char *sname, char *jname)
725 zfs_handle_t *zhp;
726 char *rest;
727 char volname[ZFS_MAX_DATASET_NAME_LEN];
728 char mountpoint[PATH_MAX];
730 if (get_zfsvolname(volname, ZFS_MAX_DATASET_NAME_LEN, name) == -1)
731 goto notzfs;
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;
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;
747 zfs_close(zhp);
748 (void) mutex_unlock(&zlib_mtx);
750 rest = name + strlen(mountpoint);
751 (void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint,
752 TLM_SNAPSHOT_DIR, jname, rest);
754 return (sname);
756 notzfs:
757 (void) strlcpy(sname, name, TLM_MAX_PATH_NAME);
758 return (sname);
762 * Remove the checkpoint from a path name.
764 * Input:
765 * name: Full pathname with checkpoint embeded.
767 * Output:
768 * unchkp_name: real pathname with no checkpoint.
770 * Returns:
771 * Pointer to the un-checkpointed path.
773 char *
774 tlm_remove_checkpoint(char *name, char *unchkp_name)
776 char *cp;
777 int i;
778 int plen;
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') {
791 * name == "/v1.chkpnt"
793 return (unchkp_name);
795 if ((cp = strchr(&name[++i], '/')) != NULL) {
796 (void) strlcat(unchkp_name, cp,
797 TLM_VOLNAME_MAX_LENGTH + 1);
799 return (unchkp_name);
800 } else {
801 unchkp_name[i] = name[i];
803 break;
804 case '/':
805 return (name);
806 case 0:
807 return (name);
808 default:
809 unchkp_name[i] = name[i];
810 break;
813 return (name);
817 * see if we should exclude this file.
819 boolean_t
820 tlm_is_excluded(char *dir, char *name, char **excl_files)
822 int i;
823 char full_name[TLM_MAX_PATH_NAME];
825 if (!dir || !name || !excl_files)
826 return (FALSE);
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);
833 for (i = 0; excl_files[i] != 0; i++) {
834 if (match(excl_files[i], full_name)) {
835 return (TRUE);
838 return (FALSE);
842 * Check if the path is too long
844 boolean_t
845 tlm_is_too_long(int checkpointed, char *dir, char *nm)
847 int nlen, tot;
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;
858 return ((tot >= PATH_MAX) ? TRUE : FALSE);
862 * Get the data offset of inside the buffer
864 longlong_t
865 tlm_get_data_offset(tlm_cmd_t *lcmds)
867 if (!lcmds)
868 return (0LL);
870 return (lcmds->tc_buffers->tbs_offset);
874 * Enable the barcode capability on the library
876 void
877 tlm_enable_barcode(int l)
879 tlm_library_t *lp;
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);
889 * SASD SCSI support
891 static scsi_adapter_t my_sa;
892 static int sasd_drive_count = 0;
893 static scsi_sasd_drive_t *scsi_sasd_drives[128];
896 * Count of SCSI devices
899 sasd_dev_count(void)
901 return (sasd_drive_count);
905 * Return the SCSI device name
907 char *
908 sasd_slink_name(scsi_link_t *slink)
910 int i;
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);
916 return (NULL);
920 * Return the SCSI drive structure
922 sasd_drive_t *
923 sasd_slink_drive(scsi_link_t *slink)
925 int i;
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);
931 return (NULL);
935 * Return the SCSI link pointer for the given index
937 scsi_link_t *
938 sasd_dev_slink(int entry)
940 scsi_link_t *rv;
942 if (entry >= 0 && entry < sasd_drive_count)
943 rv = &scsi_sasd_drives[entry]->ss_slink;
944 else
945 rv = NULL;
947 return (rv);
951 * Return the SCSI drive for the given index
953 sasd_drive_t *
954 sasd_drive(int entry)
956 sasd_drive_t *rv;
958 if (entry >= 0 && entry < sasd_drive_count)
959 rv = &scsi_sasd_drives[entry]->ss_sd;
960 else
961 rv = NULL;
963 return (rv);
967 * Attach the SCSI device by updating the structures
969 void
970 scsi_sasd_attach(scsi_adapter_t *sa, int sid, int lun, char *name,
971 int type)
973 scsi_link_t *sl, *next;
974 scsi_sasd_drive_t *ssd;
976 ssd = ndmp_malloc(sizeof (scsi_sasd_drive_t));
977 if (ssd == NULL)
978 return;
980 scsi_sasd_drives[sasd_drive_count++] = ssd;
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;
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;
1001 /* Insert slink */
1002 next = sa->sa_link_head.sl_next;
1003 sa->sa_link_head.sl_next = sl;
1004 sl->sl_next = next;
1008 * Go through the attached devices and detect the tape
1009 * and robot by checking the /dev entries
1012 probe_scsi(void)
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;
1022 /* Initialize the scsi adapter link */
1023 sa->sa_link_head.sl_next = &sa->sa_link_head;
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;
1036 if ((p = strchr(dp->d_name, 'd')) != NULL) {
1037 lun = atoi(++p);
1038 p = strchr(dp->d_name, 't');
1039 sid = atoi(++p);
1041 else
1042 sid = atoi(dp->d_name);
1044 scsi_sasd_attach(sa, 0, lun, dp->d_name,
1045 DTYPE_CHANGER);
1047 (void) closedir(dirp);
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);
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);
1065 while ((dp = readdir(dirp)) != NULL) {
1066 if ((strcmp(dp->d_name, ".") == 0) ||
1067 (strcmp(dp->d_name, "..") == 0))
1068 continue;
1070 /* Skip special modes */
1071 if (strpbrk(dp->d_name, "chlmu") != NULL)
1072 continue;
1074 /* Pick the non-rewind device */
1075 if (strchr(dp->d_name, 'n') == NULL)
1076 continue;
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;
1086 sid = atoi(dp->d_name);
1089 * SCSI ID should match with the ID of the device
1090 * (will be checked by SCSI get elements page later)
1092 scsi_sasd_attach(sa, sid, 0, dp->d_name,
1093 DTYPE_SEQUENTIAL);
1095 (void) closedir(dirp);
1098 return (0);
1102 * Get the SCSI device type (tape, robot)
1104 /*ARGSUSED*/
1106 scsi_get_devtype(char *adapter, int sid, int lun)
1108 int rv;
1109 scsi_adapter_t *sa = &my_sa;
1110 scsi_link_t *sl, *sh;
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;
1118 return (rv);
1123 * Check if the SCSI device exists
1125 /*ARGSUSED*/
1127 scsi_dev_exists(char *adapter, int sid, int lun)
1129 scsi_adapter_t *sa = &my_sa;
1130 scsi_link_t *sl, *sh;
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);
1141 * Count of SCSI adapters
1144 scsi_get_adapter_count(void)
1146 /* Currently support one adapter only */
1147 return (1);
1151 * Return the SCSI adapter structure
1153 /*ARGSUSED*/
1154 scsi_adapter_t *
1155 scsi_get_adapter(int adapter)
1157 return (&my_sa);
1161 * IOCTL wrapper with retries
1164 tlm_ioctl(int fd, int cmd, void *data)
1166 int retries = 0;
1168 NDMP_LOG(LOG_DEBUG, "tlm_ioctl fd %d cmd %d", fd, cmd);
1169 if (fd == 0 || data == NULL)
1170 return (EINVAL);
1172 do {
1173 if (ioctl(fd, cmd, data) == 0)
1174 break;
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);
1182 (void) sleep(1);
1183 } while (retries++ < MAXIORETRY);
1185 return (0);
1189 * Checkpoint or snapshot calls
1193 * Get the snapshot creation time
1196 chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp)
1198 char chk_name[PATH_MAX];
1199 zfs_handle_t *zhp;
1200 char *p;
1202 if (!volname || !*volname)
1203 return (-1);
1205 /* Should also return -1 if checkpoint not enabled */
1207 /* Remove the leading slash */
1208 p = volname;
1209 while (*p == '/')
1210 p++;
1212 (void) strlcpy(chk_name, p, PATH_MAX);
1213 (void) strlcat(chk_name, "@", PATH_MAX);
1214 (void) strlcat(chk_name, pattern, PATH_MAX);
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);
1224 *tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION);
1225 zfs_close(zhp);
1226 (void) mutex_unlock(&zlib_mtx);
1228 return (0);
1233 * Get the ZFS volume name out of the given path
1236 get_zfsvolname(char *volname, int len, char *path)
1238 struct stat64 stbuf;
1239 struct extmnttab ent;
1240 FILE *mntfp;
1241 int rv;
1243 *volname = '\0';
1244 if (stat64(path, &stbuf) != 0) {
1245 return (-1);
1248 if ((mntfp = fopen(MNTTAB, "r")) == NULL) {
1249 return (-1);
1251 while ((rv = getextmntent(mntfp, &ent, 0)) == 0) {
1252 if (makedevice(ent.mnt_major, ent.mnt_minor) ==
1253 stbuf.st_dev)
1254 break;
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;
1263 (void) fclose(mntfp);
1264 return (rv);
1269 * Check if the volume type is snapshot volume
1271 boolean_t
1272 fs_is_chkpntvol(char *path)
1274 zfs_handle_t *zhp;
1275 char vol[ZFS_MAX_DATASET_NAME_LEN];
1277 if (!path || !*path)
1278 return (FALSE);
1280 if (get_zfsvolname(vol, sizeof (vol), path) == -1)
1281 return (FALSE);
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);
1289 if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) {
1290 zfs_close(zhp);
1291 (void) mutex_unlock(&zlib_mtx);
1292 return (FALSE);
1294 zfs_close(zhp);
1295 (void) mutex_unlock(&zlib_mtx);
1297 return (TRUE);
1301 * Check if the volume is capable of checkpoints
1303 boolean_t
1304 fs_is_chkpnt_enabled(char *path)
1306 zfs_handle_t *zhp;
1307 char vol[ZFS_MAX_DATASET_NAME_LEN];
1309 if (!path || !*path)
1310 return (FALSE);
1312 (void) mutex_lock(&zlib_mtx);
1313 if (get_zfsvolname(vol, sizeof (vol), path) == -1) {
1314 (void) mutex_unlock(&zlib_mtx);
1315 return (FALSE);
1318 if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) {
1319 (void) mutex_unlock(&zlib_mtx);
1320 return (FALSE);
1322 zfs_close(zhp);
1323 (void) mutex_unlock(&zlib_mtx);
1325 return (TRUE);
1329 * Check if the volume is read-only
1331 boolean_t
1332 fs_is_rdonly(char *path)
1334 return (fs_is_chkpntvol(path));
1338 * Min/max functions
1340 unsigned
1341 min(unsigned a, unsigned b)
1343 return (a < b ? a : b);
1346 unsigned
1347 max(unsigned a, unsigned b)
1349 return (a > b ? a : b);
1352 longlong_t
1353 llmin(longlong_t a, longlong_t b)
1355 return (a < b ? a : b);