2 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
3 * Copyright (c) 2015 by Delphix. All rights reserved.
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
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
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
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>
43 #include <sys/types.h>
48 #include "tlm_proto.h"
49 #include <ndmpd_prop.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>
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
= {
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
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;
93 * make sure the allocation is in chunks of 512 bytes
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.
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
;
151 (void) memset(rec
, 0, *actual_size
);
157 * get a read record from the tape buffer,
158 * and read a tape block if necessary
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;
171 buf
= buffers
->tbs_buffer_out
;
172 buffer
= &buffers
->tbs_buffer
[buf
];
175 * make sure the allocation is in chunks of 512 bytes
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
212 current_size
= buffer
->tb_buffer_size
- buffer
->tb_buffer_spot
;
215 /* Make sure we got something */
216 if (current_size
<= 0)
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
;
236 * unread a previously read buffer back to the tape buffer
239 tlm_unget_read_buffer(tlm_buffers_t
*buffers
, int size
)
241 tlm_buffer_t
*buffer
;
242 int align_size
= RECORDSIZE
- 1;
246 buf
= buffers
->tbs_buffer_out
;
247 buffer
= &buffers
->tbs_buffer
[buf
];
250 * make sure the allocation is in chunks of 512 bytes
255 current_size
= min(size
, buffer
->tb_buffer_spot
);
256 buffer
->tb_buffer_spot
-= current_size
;
261 * unwrite a previously written buffer
264 tlm_unget_write_buffer(tlm_buffers_t
*buffers
, int size
)
266 tlm_buffer_t
*buffer
;
267 int align_size
= RECORDSIZE
- 1;
271 buf
= buffers
->tbs_buffer_in
;
272 buffer
= &buffers
->tbs_buffer
[buf
];
275 * make sure the allocation is in chunks of 512 bytes
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
289 tlm_build_header_checksum(tlm_tar_hdr_t
*r
)
295 (void) memcpy(r
->th_chksum
, CHKBLANKS
, strlen(CHKBLANKS
));
296 for (i
= 0; i
< RECORDSIZE
; i
++) {
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
++) {
322 "should be %d, is 0", chksum
);
323 /* a zero record ==> end of tar file */
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
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
)
360 dp
= tlm_drive(lib
, drv
);
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)",
369 /* search through the SASD table */
370 n
= sasd_dev_count();
371 for (i
= 0; i
< n
; i
++) {
372 sl
= sasd_dev_slink(i
);
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 */
390 * get the OS device name for this tape
393 tlm_get_tape_name(int lib
, int drv
)
397 entry
= tlm_get_scsi_sasd_entry(lib
, drv
);
401 if ((sd
= sasd_drive(entry
)) != 0)
402 return (sd
->sd_name
);
409 * create the IPC area between the reader and writer
412 tlm_create_reader_writer_ipc(boolean_t write
, long data_transfer_size
)
416 cmd
= ndmp_malloc(sizeof (tlm_cmd_t
));
420 cmd
->tc_reader
= TLM_BACKUP_RUN
;
421 cmd
->tc_writer
= TLM_BACKUP_RUN
;
424 cmd
->tc_buffers
= tlm_allocate_buffers(write
, data_transfer_size
);
425 if (cmd
->tc_buffers
== NULL
) {
430 (void) mutex_init(&cmd
->tc_mtx
, 0, NULL
);
431 (void) cond_init(&cmd
->tc_cv
, 0, NULL
);
437 * release(destroy) the IPC between the reader and writer
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
);
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
));
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
;
478 * Cleanup the callbacks
481 lbrlog_callbacks_done(lbr_fhlog_call_backs_t
*p
)
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
,
495 lbr_fhlog_call_backs_t
*cbp
; /* callbacks pointer */
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
)
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");
510 rv
= (*cbp
->fh_log_dir
)(cbp
, dir
, stp
, fhp
);
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
)
523 lbr_fhlog_call_backs_t
*cbp
; /* callbacks pointer */
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
)
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");
540 rv
= (*cbp
->fh_log_node
)(cbp
, dir
, file
, stp
, off
);
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
)
553 lbr_fhlog_call_backs_t
*cbp
; /* callbacks pointer */
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");
561 NDMP_LOG(LOG_DEBUG
, "log_fhpath_name: stp is NULL");
562 } else if ((cbp
= (lbr_fhlog_call_backs_t
*)job_stats
->js_callbacks
)
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");
568 rv
= (*cbp
->fh_logpname
)(cbp
, pathname
, stp
, off
);
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");
588 cbp
= (lbr_fhlog_call_backs_t
*)job_stats
->js_callbacks
;
590 NDMP_LOG(LOG_DEBUG
, "entry_restored is NULL");
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.
608 * char *buf - buffer to write new dir/name string
609 * char *dir - directory name
610 * char *name - file name
613 * TRUE - No errors. buf contains the dir/name string
614 * FALSE - Error. buf is not modified.
617 tlm_cat_path(char *buf
, char *dir
, char *name
)
620 int dirlen
= strlen(dir
);
621 int filelen
= strlen(name
);
623 if ((dirlen
+ filelen
+ 1) >= PATH_MAX
) {
627 if (*dir
== '\0' || *name
== '\0' || dir
[dirlen
- 1] == '/' ||
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
);
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
];
655 NDMP_LOG(LOG_DEBUG
, "path [%s] auto_checkpoint: %d",
656 path
, auto_checkpoint
);
658 if (path
== NULL
|| *path
== '\0' || tp
== NULL
)
661 if (get_zfsvolname(volname
, TLM_VOLNAME_MAX_LENGTH
,
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.
680 tlm_release_list(char **lpp
)
684 if ((save
= lpp
) == 0)
694 * Print the list of array of strings in the backup log
697 tlm_log_list(char *title
, char **lpp
)
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.
714 * name: Original path name.
717 * name: Original name modified to include a snapshot.
720 * Original name modified to include a snapshot.
723 tlm_build_snapshot_name(char *name
, char *sname
, char *jname
)
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)
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
);
740 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, mountpoint
, PATH_MAX
, NULL
,
741 NULL
, 0, B_FALSE
) != 0) {
743 (void) mutex_unlock(&zlib_mtx
);
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
);
757 (void) strlcpy(sname
, name
, TLM_MAX_PATH_NAME
);
762 * Remove the checkpoint from a path name.
765 * name: Full pathname with checkpoint embeded.
768 * unchkp_name: real pathname with no checkpoint.
771 * Pointer to the un-checkpointed path.
774 tlm_remove_checkpoint(char *name
, char *unchkp_name
)
780 unchkp_name
[0] = name
[0];
781 plen
= strlen(TLM_SNAPSHOT_PREFIX
);
782 for (i
= 1; i
<= TLM_VOLNAME_MAX_LENGTH
+ 1; i
++) {
785 if (strncmp(&name
[i
], TLM_SNAPSHOT_PREFIX
,
787 unchkp_name
[i
] = '\0';
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
);
801 unchkp_name
[i
] = name
[i
];
809 unchkp_name
[i
] = name
[i
];
817 * see if we should exclude this file.
820 tlm_is_excluded(char *dir
, char *name
, char **excl_files
)
823 char full_name
[TLM_MAX_PATH_NAME
];
825 if (!dir
|| !name
|| !excl_files
)
828 if (!tlm_cat_path(full_name
, dir
, name
)) {
829 NDMP_LOG(LOG_DEBUG
, "Path too long [%s][%s]",
833 for (i
= 0; excl_files
[i
] != 0; i
++) {
834 if (match(excl_files
[i
], full_name
)) {
842 * Check if the path is too long
845 tlm_is_too_long(int checkpointed
, char *dir
, char *nm
)
853 tot
+= strlen(TLM_SNAPSHOT_DIR
) + 1;
855 if ((nlen
= strlen(nm
)) > 0)
858 return ((tot
>= PATH_MAX
) ? TRUE
: FALSE
);
862 * Get the data offset of inside the buffer
865 tlm_get_data_offset(tlm_cmd_t
*lcmds
)
870 return (lcmds
->tc_buffers
->tbs_offset
);
874 * Enable the barcode capability on the library
877 tlm_enable_barcode(int l
)
881 if ((lp
= tlm_library(l
))) {
882 lp
->tl_capability_barcodes
= TRUE
;
884 "Barcode capability on library %d enabled.", l
);
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
901 return (sasd_drive_count
);
905 * Return the SCSI device name
908 sasd_slink_name(scsi_link_t
*slink
)
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
);
920 * Return the SCSI drive structure
923 sasd_slink_drive(scsi_link_t
*slink
)
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
);
935 * Return the SCSI link pointer for the given index
938 sasd_dev_slink(int entry
)
942 if (entry
>= 0 && entry
< sasd_drive_count
)
943 rv
= &scsi_sasd_drives
[entry
]->ss_slink
;
951 * Return the SCSI drive for the given index
954 sasd_drive(int entry
)
958 if (entry
>= 0 && entry
< sasd_drive_count
)
959 rv
= &scsi_sasd_drives
[entry
]->ss_sd
;
967 * Attach the SCSI device by updating the structures
970 scsi_sasd_attach(scsi_adapter_t
*sa
, int sid
, int lun
, char *name
,
973 scsi_link_t
*sl
, *next
;
974 scsi_sasd_drive_t
*ssd
;
976 ssd
= ndmp_malloc(sizeof (scsi_sasd_drive_t
));
980 scsi_sasd_drives
[sasd_drive_count
++] = ssd
;
984 (void) snprintf(ssd
->ss_sd
.sd_name
,
985 sizeof (ssd
->ss_sd
.sd_name
), "%s/%s", SCSI_CHANGER_DIR
,
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
);
999 sl
->sl_requested_max_active
= 1;
1002 next
= sa
->sa_link_head
.sl_next
;
1003 sa
->sa_link_head
.sl_next
= sl
;
1008 * Go through the attached devices and detect the tape
1009 * and robot by checking the /dev entries
1016 scsi_adapter_t
*sa
= &my_sa
;
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
);
1029 "Changer directory read error %s", SCSI_CHANGER_DIR
);
1031 while ((dp
= readdir(dirp
)) != NULL
) {
1032 if ((strcmp(dp
->d_name
, ".") == 0) ||
1033 (strcmp(dp
->d_name
, "..") == 0))
1036 if ((p
= strchr(dp
->d_name
, 'd')) != NULL
) {
1038 p
= strchr(dp
->d_name
, 't');
1042 sid
= atoi(dp
->d_name
);
1044 scsi_sasd_attach(sa
, 0, lun
, dp
->d_name
,
1047 (void) closedir(dirp
);
1050 /* Scan for tape drives */
1051 dirp
= opendir(SCSI_TAPE_DIR
);
1054 "Tape directory read error %s", SCSI_TAPE_DIR
);
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'.");
1065 while ((dp
= readdir(dirp
)) != NULL
) {
1066 if ((strcmp(dp
->d_name
, ".") == 0) ||
1067 (strcmp(dp
->d_name
, "..") == 0))
1070 /* Skip special modes */
1071 if (strpbrk(dp
->d_name
, "chlmu") != NULL
)
1074 /* Pick the non-rewind device */
1075 if (strchr(dp
->d_name
, 'n') == NULL
)
1078 if (strcasecmp(drive_type
, "sysv") == 0) {
1079 if (strchr(dp
->d_name
, 'b') != NULL
)
1081 } else if (strcasecmp(drive_type
, "bsd") == 0) {
1082 if (strchr(dp
->d_name
, 'b') == NULL
)
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
,
1095 (void) closedir(dirp
);
1102 * Get the SCSI device type (tape, robot)
1106 scsi_get_devtype(char *adapter
, int sid
, int lun
)
1109 scsi_adapter_t
*sa
= &my_sa
;
1110 scsi_link_t
*sl
, *sh
;
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
)
1123 * Check if the SCSI device exists
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
)
1141 * Count of SCSI adapters
1144 scsi_get_adapter_count(void)
1146 /* Currently support one adapter only */
1151 * Return the SCSI adapter structure
1155 scsi_get_adapter(int adapter
)
1161 * IOCTL wrapper with retries
1164 tlm_ioctl(int fd
, int cmd
, void *data
)
1168 NDMP_LOG(LOG_DEBUG
, "tlm_ioctl fd %d cmd %d", fd
, cmd
);
1169 if (fd
== 0 || data
== NULL
)
1173 if (ioctl(fd
, cmd
, data
) == 0)
1176 if (errno
!= EIO
&& errno
!= 0) {
1178 "Failed to send command to device: %m.");
1179 NDMP_LOG(LOG_DEBUG
, "IOCTL error %d", errno
);
1183 } while (retries
++ < MAXIORETRY
);
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
];
1202 if (!volname
|| !*volname
)
1205 /* Should also return -1 if checkpoint not enabled */
1207 /* Remove the leading slash */
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",
1220 (void) mutex_unlock(&zlib_mtx
);
1224 *tp
= zfs_prop_get_int(zhp
, ZFS_PROP_CREATION
);
1226 (void) mutex_unlock(&zlib_mtx
);
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
;
1244 if (stat64(path
, &stbuf
) != 0) {
1248 if ((mntfp
= fopen(MNTTAB
, "r")) == NULL
) {
1251 while ((rv
= getextmntent(mntfp
, &ent
, 0)) == 0) {
1252 if (makedevice(ent
.mnt_major
, ent
.mnt_minor
) ==
1258 strcmp(ent
.mnt_fstype
, MNTTYPE_ZFS
) == 0)
1259 (void) strlcpy(volname
, ent
.mnt_special
, len
);
1263 (void) fclose(mntfp
);
1269 * Check if the volume type is snapshot volume
1272 fs_is_chkpntvol(char *path
)
1275 char vol
[ZFS_MAX_DATASET_NAME_LEN
];
1277 if (!path
|| !*path
)
1280 if (get_zfsvolname(vol
, sizeof (vol
), path
) == -1)
1283 (void) mutex_lock(&zlib_mtx
);
1284 if ((zhp
= zfs_open(zlibh
, vol
, ZFS_TYPE_DATASET
)) == NULL
) {
1285 (void) mutex_unlock(&zlib_mtx
);
1289 if (zfs_get_type(zhp
) != ZFS_TYPE_SNAPSHOT
) {
1291 (void) mutex_unlock(&zlib_mtx
);
1295 (void) mutex_unlock(&zlib_mtx
);
1301 * Check if the volume is capable of checkpoints
1304 fs_is_chkpnt_enabled(char *path
)
1307 char vol
[ZFS_MAX_DATASET_NAME_LEN
];
1309 if (!path
|| !*path
)
1312 (void) mutex_lock(&zlib_mtx
);
1313 if (get_zfsvolname(vol
, sizeof (vol
), path
) == -1) {
1314 (void) mutex_unlock(&zlib_mtx
);
1318 if ((zhp
= zfs_open(zlibh
, vol
, ZFS_TYPE_DATASET
)) == NULL
) {
1319 (void) mutex_unlock(&zlib_mtx
);
1323 (void) mutex_unlock(&zlib_mtx
);
1329 * Check if the volume is read-only
1332 fs_is_rdonly(char *path
)
1334 return (fs_is_chkpntvol(path
));
1341 min(unsigned a
, unsigned b
)
1343 return (a
< b
? a
: b
);
1347 max(unsigned a
, unsigned b
)
1349 return (a
> b
? a
: b
);
1353 llmin(longlong_t a
, longlong_t b
)
1355 return (a
< b
? a
: b
);