12654012fSReza Sabdar /* 28c4f9701SJanice Chang * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 3*40a5c998SMatthew Ahrens * Copyright (c) 2015 by Delphix. All rights reserved. 42654012fSReza Sabdar */ 52654012fSReza Sabdar 62654012fSReza Sabdar /* 72654012fSReza Sabdar * BSD 3 Clause License 82654012fSReza Sabdar * 92654012fSReza Sabdar * Copyright (c) 2007, The Storage Networking Industry Association. 102654012fSReza Sabdar * 112654012fSReza Sabdar * Redistribution and use in source and binary forms, with or without 122654012fSReza Sabdar * modification, are permitted provided that the following conditions 132654012fSReza Sabdar * are met: 142654012fSReza Sabdar * - Redistributions of source code must retain the above copyright 152654012fSReza Sabdar * notice, this list of conditions and the following disclaimer. 162654012fSReza Sabdar * 172654012fSReza Sabdar * - Redistributions in binary form must reproduce the above copyright 182654012fSReza Sabdar * notice, this list of conditions and the following disclaimer in 192654012fSReza Sabdar * the documentation and/or other materials provided with the 202654012fSReza Sabdar * distribution. 212654012fSReza Sabdar * 222654012fSReza Sabdar * - Neither the name of The Storage Networking Industry Association (SNIA) 232654012fSReza Sabdar * nor the names of its contributors may be used to endorse or promote 242654012fSReza Sabdar * products derived from this software without specific prior written 252654012fSReza Sabdar * permission. 262654012fSReza Sabdar * 272654012fSReza Sabdar * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 282654012fSReza Sabdar * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 292654012fSReza Sabdar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 302654012fSReza Sabdar * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 312654012fSReza Sabdar * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 322654012fSReza Sabdar * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 332654012fSReza Sabdar * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 342654012fSReza Sabdar * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 352654012fSReza Sabdar * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 362654012fSReza Sabdar * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 372654012fSReza Sabdar * POSSIBILITY OF SUCH DAMAGE. 382654012fSReza Sabdar */ 392654012fSReza Sabdar #include <sys/errno.h> 402654012fSReza Sabdar #include <ctype.h> 412654012fSReza Sabdar #include <stdlib.h> 422654012fSReza Sabdar #include <time.h> 432654012fSReza Sabdar #include <sys/types.h> 442654012fSReza Sabdar #include <unistd.h> 452654012fSReza Sabdar #include <libzfs.h> 462654012fSReza Sabdar #include <pthread.h> 472654012fSReza Sabdar #include "tlm.h" 482654012fSReza Sabdar #include "tlm_proto.h" 491e05b03fSJanice Chang #include <ndmpd_prop.h> 502654012fSReza Sabdar #include <sys/mtio.h> 512654012fSReza Sabdar #include <sys/mnttab.h> 522654012fSReza Sabdar #include <sys/mntent.h> 532654012fSReza Sabdar #include <sys/statvfs.h> 542654012fSReza Sabdar #include <sys/scsi/impl/uscsi.h> 552654012fSReza Sabdar #include <sys/scsi/scsi.h> 562654012fSReza Sabdar #include <sys/mtio.h> 572654012fSReza Sabdar #include <thread.h> 582654012fSReza Sabdar #include <synch.h> 592654012fSReza Sabdar #include <sys/mutex.h> 602654012fSReza Sabdar #include <sys/sysmacros.h> 612654012fSReza Sabdar #include <sys/mkdev.h> 622654012fSReza Sabdar 632654012fSReza Sabdar /* 642654012fSReza Sabdar * Tar archiving ops vector 652654012fSReza Sabdar */ 662654012fSReza Sabdar tm_ops_t tm_tar_ops = { 672654012fSReza Sabdar "tar", 682654012fSReza Sabdar tar_putfile, 692654012fSReza Sabdar tar_putdir, 702654012fSReza Sabdar NULL, 712654012fSReza Sabdar tar_getfile, 722654012fSReza Sabdar tar_getdir, 732654012fSReza Sabdar NULL 742654012fSReza Sabdar }; 752654012fSReza Sabdar 762654012fSReza Sabdar extern libzfs_handle_t *zlibh; 772654012fSReza Sabdar extern mutex_t zlib_mtx; 782654012fSReza Sabdar 792654012fSReza Sabdar /* 802654012fSReza Sabdar * get the next tape buffer from the drive's pool of buffers 812654012fSReza Sabdar */ 822654012fSReza Sabdar /*ARGSUSED*/ 832654012fSReza Sabdar char * 842654012fSReza Sabdar tlm_get_write_buffer(long want, long *actual_size, 852654012fSReza Sabdar tlm_buffers_t *buffers, int zero) 862654012fSReza Sabdar { 872654012fSReza Sabdar int buf = buffers->tbs_buffer_in; 882654012fSReza Sabdar tlm_buffer_t *buffer = &buffers->tbs_buffer[buf]; 892654012fSReza Sabdar int align_size = RECORDSIZE - 1; 902654012fSReza Sabdar char *rec; 912654012fSReza Sabdar 922654012fSReza Sabdar /* 932654012fSReza Sabdar * make sure the allocation is in chunks of 512 bytes 942654012fSReza Sabdar */ 952654012fSReza Sabdar want += align_size; 962654012fSReza Sabdar want &= ~align_size; 972654012fSReza Sabdar 982654012fSReza Sabdar *actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot; 992654012fSReza Sabdar if (*actual_size <= 0) { 1002654012fSReza Sabdar /* 1012654012fSReza Sabdar * no room, send this one 1022654012fSReza Sabdar * and wait for a free one 1032654012fSReza Sabdar */ 1042654012fSReza Sabdar if (!buffer->tb_full) { 1052654012fSReza Sabdar /* 1062654012fSReza Sabdar * we are now ready to send a full buffer 1072654012fSReza Sabdar * instead of trying to get a new buffer 1082654012fSReza Sabdar * 1092654012fSReza Sabdar * do not send if we failed to get a buffer 1102654012fSReza Sabdar * on the previous call 1112654012fSReza Sabdar */ 1122654012fSReza Sabdar buffer->tb_full = TRUE; 1132654012fSReza Sabdar 1142654012fSReza Sabdar /* 1152654012fSReza Sabdar * tell the writer that a buffer is available 1162654012fSReza Sabdar */ 1172654012fSReza Sabdar tlm_buffer_release_in_buf(buffers); 1182654012fSReza Sabdar 1192654012fSReza Sabdar buffer = tlm_buffer_advance_in_idx(buffers); 1202654012fSReza Sabdar } 1212654012fSReza Sabdar 1222654012fSReza Sabdar buffer = tlm_buffer_in_buf(buffers, NULL); 1232654012fSReza Sabdar 1242654012fSReza Sabdar if (buffer->tb_full) { 1252654012fSReza Sabdar /* 1262654012fSReza Sabdar * wait for the writer to free up a buffer 1272654012fSReza Sabdar */ 1282654012fSReza Sabdar tlm_buffer_out_buf_timed_wait(buffers, 500); 1292654012fSReza Sabdar } 1302654012fSReza Sabdar 1312654012fSReza Sabdar buffer = tlm_buffer_in_buf(buffers, NULL); 1322654012fSReza Sabdar if (buffer->tb_full) { 1332654012fSReza Sabdar /* 1342654012fSReza Sabdar * the next buffer is still full 1352654012fSReza Sabdar * of data from previous activity 1362654012fSReza Sabdar * 1372654012fSReza Sabdar * nothing has changed. 1382654012fSReza Sabdar */ 1392654012fSReza Sabdar return (0); 1402654012fSReza Sabdar } 1412654012fSReza Sabdar 1422654012fSReza Sabdar buffer->tb_buffer_spot = 0; 1432654012fSReza Sabdar *actual_size = buffer->tb_buffer_size - buffer->tb_buffer_spot; 1442654012fSReza Sabdar } 1452654012fSReza Sabdar 1462654012fSReza Sabdar *actual_size = min(want, *actual_size); 1472654012fSReza Sabdar rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot]; 1482654012fSReza Sabdar buffer->tb_buffer_spot += *actual_size; 1492654012fSReza Sabdar buffers->tbs_offset += *actual_size; 1502654012fSReza Sabdar if (zero) { 1512654012fSReza Sabdar (void) memset(rec, 0, *actual_size); 1522654012fSReza Sabdar } 1532654012fSReza Sabdar return (rec); 1542654012fSReza Sabdar } 1552654012fSReza Sabdar 1562654012fSReza Sabdar /* 1572654012fSReza Sabdar * get a read record from the tape buffer, 1582654012fSReza Sabdar * and read a tape block if necessary 1592654012fSReza Sabdar */ 1602654012fSReza Sabdar /*ARGSUSED*/ 1612654012fSReza Sabdar char * 1622654012fSReza Sabdar tlm_get_read_buffer(int want, int *error, 1632654012fSReza Sabdar tlm_buffers_t *buffers, int *actual_size) 1642654012fSReza Sabdar { 1652654012fSReza Sabdar tlm_buffer_t *buffer; 1662654012fSReza Sabdar int align_size = RECORDSIZE - 1; 1672654012fSReza Sabdar int buf; 1682654012fSReza Sabdar int current_size; 1692654012fSReza Sabdar char *rec; 1702654012fSReza Sabdar 1712654012fSReza Sabdar buf = buffers->tbs_buffer_out; 1722654012fSReza Sabdar buffer = &buffers->tbs_buffer[buf]; 1732654012fSReza Sabdar 1742654012fSReza Sabdar /* 1752654012fSReza Sabdar * make sure the allocation is in chunks of 512 bytes 1762654012fSReza Sabdar */ 1772654012fSReza Sabdar want += align_size; 1782654012fSReza Sabdar want &= ~align_size; 1792654012fSReza Sabdar 1802654012fSReza Sabdar current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot; 1812654012fSReza Sabdar if (buffer->tb_full && current_size <= 0) { 1822654012fSReza Sabdar /* 1832654012fSReza Sabdar * no more data, release this 1842654012fSReza Sabdar * one and go get another 1852654012fSReza Sabdar */ 1862654012fSReza Sabdar 1872654012fSReza Sabdar /* 1882654012fSReza Sabdar * tell the reader that a buffer is available 1892654012fSReza Sabdar */ 1902654012fSReza Sabdar buffer->tb_full = FALSE; 1912654012fSReza Sabdar tlm_buffer_release_out_buf(buffers); 1922654012fSReza Sabdar 1932654012fSReza Sabdar buffer = tlm_buffer_advance_out_idx(buffers); 1942654012fSReza Sabdar current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot; 1952654012fSReza Sabdar } 1962654012fSReza Sabdar 1972654012fSReza Sabdar if (!buffer->tb_full) { 1982654012fSReza Sabdar /* 1992654012fSReza Sabdar * next buffer is not full yet. 2002654012fSReza Sabdar * wait for the reader. 2012654012fSReza Sabdar */ 2022654012fSReza Sabdar tlm_buffer_in_buf_timed_wait(buffers, 500); 2032654012fSReza Sabdar 2042654012fSReza Sabdar buffer = tlm_buffer_out_buf(buffers, NULL); 2052654012fSReza Sabdar if (!buffer->tb_full) { 2062654012fSReza Sabdar /* 2072654012fSReza Sabdar * we do not have anything from the tape yet 2082654012fSReza Sabdar */ 2092654012fSReza Sabdar return (0); 2102654012fSReza Sabdar } 2112654012fSReza Sabdar 2122654012fSReza Sabdar current_size = buffer->tb_buffer_size - buffer->tb_buffer_spot; 2132654012fSReza Sabdar } 2142654012fSReza Sabdar 2152654012fSReza Sabdar /* Make sure we got something */ 2162654012fSReza Sabdar if (current_size <= 0) 2172654012fSReza Sabdar return (NULL); 2182654012fSReza Sabdar 2192654012fSReza Sabdar current_size = min(want, current_size); 2202654012fSReza Sabdar rec = &buffer->tb_buffer_data[buffer->tb_buffer_spot]; 2212654012fSReza Sabdar buffer->tb_buffer_spot += current_size; 2222654012fSReza Sabdar *actual_size = current_size; 2232654012fSReza Sabdar 2242654012fSReza Sabdar /* 2252654012fSReza Sabdar * the error flag is only sent back one time, 2262654012fSReza Sabdar * since the flag refers to a previous read 2272654012fSReza Sabdar * attempt, not the data in this buffer. 2282654012fSReza Sabdar */ 2292654012fSReza Sabdar *error = buffer->tb_errno; 2302654012fSReza Sabdar 2312654012fSReza Sabdar return (rec); 2322654012fSReza Sabdar } 2332654012fSReza Sabdar 2342654012fSReza Sabdar 2352654012fSReza Sabdar /* 2362654012fSReza Sabdar * unread a previously read buffer back to the tape buffer 2372654012fSReza Sabdar */ 2382654012fSReza Sabdar void 2392654012fSReza Sabdar tlm_unget_read_buffer(tlm_buffers_t *buffers, int size) 2402654012fSReza Sabdar { 2412654012fSReza Sabdar tlm_buffer_t *buffer; 2422654012fSReza Sabdar int align_size = RECORDSIZE - 1; 2432654012fSReza Sabdar int buf; 2442654012fSReza Sabdar int current_size; 2452654012fSReza Sabdar 2462654012fSReza Sabdar buf = buffers->tbs_buffer_out; 2472654012fSReza Sabdar buffer = &buffers->tbs_buffer[buf]; 2482654012fSReza Sabdar 2492654012fSReza Sabdar /* 2502654012fSReza Sabdar * make sure the allocation is in chunks of 512 bytes 2512654012fSReza Sabdar */ 2522654012fSReza Sabdar size += align_size; 2532654012fSReza Sabdar size &= ~align_size; 2542654012fSReza Sabdar 2552654012fSReza Sabdar current_size = min(size, buffer->tb_buffer_spot); 2562654012fSReza Sabdar buffer->tb_buffer_spot -= current_size; 2572654012fSReza Sabdar } 2582654012fSReza Sabdar 2592654012fSReza Sabdar 2602654012fSReza Sabdar /* 2612654012fSReza Sabdar * unwrite a previously written buffer 2622654012fSReza Sabdar */ 2632654012fSReza Sabdar void 2642654012fSReza Sabdar tlm_unget_write_buffer(tlm_buffers_t *buffers, int size) 2652654012fSReza Sabdar { 2662654012fSReza Sabdar tlm_buffer_t *buffer; 2672654012fSReza Sabdar int align_size = RECORDSIZE - 1; 2682654012fSReza Sabdar int buf; 2692654012fSReza Sabdar int current_size; 2702654012fSReza Sabdar 2712654012fSReza Sabdar buf = buffers->tbs_buffer_in; 2722654012fSReza Sabdar buffer = &buffers->tbs_buffer[buf]; 2732654012fSReza Sabdar 2742654012fSReza Sabdar /* 2752654012fSReza Sabdar * make sure the allocation is in chunks of 512 bytes 2762654012fSReza Sabdar */ 2772654012fSReza Sabdar size += align_size; 2782654012fSReza Sabdar size &= ~align_size; 2792654012fSReza Sabdar 2802654012fSReza Sabdar current_size = min(size, buffer->tb_buffer_spot); 2812654012fSReza Sabdar buffer->tb_buffer_spot -= current_size; 2822654012fSReza Sabdar } 2832654012fSReza Sabdar 2842654012fSReza Sabdar 2852654012fSReza Sabdar /* 2862654012fSReza Sabdar * build a checksum for a TAR header record 2872654012fSReza Sabdar */ 2882654012fSReza Sabdar void 2892654012fSReza Sabdar tlm_build_header_checksum(tlm_tar_hdr_t *r) 2902654012fSReza Sabdar { 2912654012fSReza Sabdar int i; 2922654012fSReza Sabdar int sum = 0; 2932654012fSReza Sabdar char *c = (char *)r; 2942654012fSReza Sabdar 2952654012fSReza Sabdar (void) memcpy(r->th_chksum, CHKBLANKS, strlen(CHKBLANKS)); 2962654012fSReza Sabdar for (i = 0; i < RECORDSIZE; i++) { 2972654012fSReza Sabdar sum += c[i] & 0xFF; 2982654012fSReza Sabdar } 2992654012fSReza Sabdar (void) snprintf(r->th_chksum, sizeof (r->th_chksum), "%6o", sum); 3002654012fSReza Sabdar } 3012654012fSReza Sabdar 3022654012fSReza Sabdar /* 3032654012fSReza Sabdar * verify the tar header checksum 3042654012fSReza Sabdar */ 3052654012fSReza Sabdar int 3062654012fSReza Sabdar tlm_vfy_tar_checksum(tlm_tar_hdr_t *tar_hdr) 3072654012fSReza Sabdar { 3082654012fSReza Sabdar int chksum = oct_atoi(tar_hdr->th_chksum); 3092654012fSReza Sabdar uchar_t *p = (uchar_t *)tar_hdr; 3102654012fSReza Sabdar int sum = 0; /* initial value of checksum */ 3112654012fSReza Sabdar int i; /* loop counter */ 3122654012fSReza Sabdar 3132654012fSReza Sabdar /* 3142654012fSReza Sabdar * compute the checksum 3152654012fSReza Sabdar */ 3162654012fSReza Sabdar for (i = 0; i < RECORDSIZE; i++) { 3172654012fSReza Sabdar sum += p[i] & 0xFF; 3182654012fSReza Sabdar } 3192654012fSReza Sabdar 3202654012fSReza Sabdar if (sum == 0) { 3212654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 3222654012fSReza Sabdar "should be %d, is 0", chksum); 3232654012fSReza Sabdar /* a zero record ==> end of tar file */ 3242654012fSReza Sabdar return (0); 3252654012fSReza Sabdar } 3262654012fSReza Sabdar 3272654012fSReza Sabdar /* 3282654012fSReza Sabdar * subtract out the label's checksum values 3292654012fSReza Sabdar * this lets us undo the old checksum "in- 3302654012fSReza Sabdar * place", no need to swap blanks in and out 3312654012fSReza Sabdar */ 3322654012fSReza Sabdar for (i = 0; i < 8; i++) { 3332654012fSReza Sabdar sum -= 0xFF & tar_hdr->th_chksum[i]; 3342654012fSReza Sabdar } 3352654012fSReza Sabdar 3362654012fSReza Sabdar /* 3372654012fSReza Sabdar * replace the old checksum field with blanks 3382654012fSReza Sabdar */ 3392654012fSReza Sabdar sum += ' ' * 8; 3402654012fSReza Sabdar 3412654012fSReza Sabdar if (sum != chksum) 3422654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 3432654012fSReza Sabdar "should be %d, is %d", chksum, sum); 3442654012fSReza Sabdar 3452654012fSReza Sabdar return ((sum == chksum) ? 1 : -1); 3462654012fSReza Sabdar } 3472654012fSReza Sabdar 3482654012fSReza Sabdar /* 3492654012fSReza Sabdar * get internal scsi_sasd entry for this tape drive 3502654012fSReza Sabdar */ 3512654012fSReza Sabdar int 3522654012fSReza Sabdar tlm_get_scsi_sasd_entry(int lib, int drv) 3532654012fSReza Sabdar { 3542654012fSReza Sabdar int entry; 3552654012fSReza Sabdar int i, n; 3562654012fSReza Sabdar scsi_link_t *sl; 3572654012fSReza Sabdar tlm_drive_t *dp; 3582654012fSReza Sabdar 3592654012fSReza Sabdar entry = -1; 3602654012fSReza Sabdar dp = tlm_drive(lib, drv); 3612654012fSReza Sabdar if (!dp) { 3622654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "NULL dp for (%d.%d)", lib, drv); 3632654012fSReza Sabdar } else if (!dp->td_slink) { 3642654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink for (%d.%d)", lib, drv); 3652654012fSReza Sabdar } else if (!dp->td_slink->sl_sa) { 3662654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "NULL dp->td_slink->sl_sa for (%d.%d)", 3672654012fSReza Sabdar lib, drv); 3682654012fSReza Sabdar } else { 3692654012fSReza Sabdar /* search through the SASD table */ 3702654012fSReza Sabdar n = sasd_dev_count(); 3712654012fSReza Sabdar for (i = 0; i < n; i++) { 3722654012fSReza Sabdar sl = sasd_dev_slink(i); 3732654012fSReza Sabdar if (!sl) 3742654012fSReza Sabdar continue; 3752654012fSReza Sabdar 3762654012fSReza Sabdar if (dp->td_slink->sl_sa == sl->sl_sa && 3772654012fSReza Sabdar dp->td_scsi_id == sl->sl_sid && 3782654012fSReza Sabdar dp->td_lun == sl->sl_lun) { 3792654012fSReza Sabdar /* all 3 variables match */ 3802654012fSReza Sabdar entry = i; 3812654012fSReza Sabdar break; 3822654012fSReza Sabdar } 3832654012fSReza Sabdar } 3842654012fSReza Sabdar } 3852654012fSReza Sabdar 3862654012fSReza Sabdar return (entry); 3872654012fSReza Sabdar } 3882654012fSReza Sabdar 3892654012fSReza Sabdar /* 3902654012fSReza Sabdar * get the OS device name for this tape 3912654012fSReza Sabdar */ 3922654012fSReza Sabdar char * 3932654012fSReza Sabdar tlm_get_tape_name(int lib, int drv) 3942654012fSReza Sabdar { 3952654012fSReza Sabdar int entry; 3962654012fSReza Sabdar 3972654012fSReza Sabdar entry = tlm_get_scsi_sasd_entry(lib, drv); 3982654012fSReza Sabdar if (entry >= 0) { 3992654012fSReza Sabdar sasd_drive_t *sd; 4002654012fSReza Sabdar 4012654012fSReza Sabdar if ((sd = sasd_drive(entry)) != 0) 4022654012fSReza Sabdar return (sd->sd_name); 4032654012fSReza Sabdar } 4042654012fSReza Sabdar 4052654012fSReza Sabdar return (""); 4062654012fSReza Sabdar } 4072654012fSReza Sabdar 4082654012fSReza Sabdar /* 4092654012fSReza Sabdar * create the IPC area between the reader and writer 4102654012fSReza Sabdar */ 4112654012fSReza Sabdar tlm_cmd_t * 4122654012fSReza Sabdar tlm_create_reader_writer_ipc(boolean_t write, long data_transfer_size) 4132654012fSReza Sabdar { 4142654012fSReza Sabdar tlm_cmd_t *cmd; 4152654012fSReza Sabdar 4162654012fSReza Sabdar cmd = ndmp_malloc(sizeof (tlm_cmd_t)); 4172654012fSReza Sabdar if (cmd == NULL) 4182654012fSReza Sabdar return (NULL); 4192654012fSReza Sabdar 4202654012fSReza Sabdar cmd->tc_reader = TLM_BACKUP_RUN; 4212654012fSReza Sabdar cmd->tc_writer = TLM_BACKUP_RUN; 4222654012fSReza Sabdar cmd->tc_ref = 1; 4232654012fSReza Sabdar 4242654012fSReza Sabdar cmd->tc_buffers = tlm_allocate_buffers(write, data_transfer_size); 4252654012fSReza Sabdar if (cmd->tc_buffers == NULL) { 4262654012fSReza Sabdar free(cmd); 4272654012fSReza Sabdar return (NULL); 4282654012fSReza Sabdar } 4292654012fSReza Sabdar 4302654012fSReza Sabdar (void) mutex_init(&cmd->tc_mtx, 0, NULL); 4312654012fSReza Sabdar (void) cond_init(&cmd->tc_cv, 0, NULL); 4322654012fSReza Sabdar 4332654012fSReza Sabdar return (cmd); 4342654012fSReza Sabdar } 4352654012fSReza Sabdar 4362654012fSReza Sabdar /* 4372654012fSReza Sabdar * release(destroy) the IPC between the reader and writer 4382654012fSReza Sabdar */ 4392654012fSReza Sabdar void 4402654012fSReza Sabdar tlm_release_reader_writer_ipc(tlm_cmd_t *cmd) 4412654012fSReza Sabdar { 4422654012fSReza Sabdar if (--cmd->tc_ref <= 0) { 4432654012fSReza Sabdar (void) mutex_lock(&cmd->tc_mtx); 4442654012fSReza Sabdar tlm_release_buffers(cmd->tc_buffers); 4452654012fSReza Sabdar (void) cond_destroy(&cmd->tc_cv); 4462654012fSReza Sabdar (void) mutex_unlock(&cmd->tc_mtx); 4472654012fSReza Sabdar (void) mutex_destroy(&cmd->tc_mtx); 4482654012fSReza Sabdar free(cmd); 4492654012fSReza Sabdar } 4502654012fSReza Sabdar } 4512654012fSReza Sabdar 4522654012fSReza Sabdar 4532654012fSReza Sabdar /* 4542654012fSReza Sabdar * NDMP support begins here. 4552654012fSReza Sabdar */ 4562654012fSReza Sabdar 4572654012fSReza Sabdar /* 4582654012fSReza Sabdar * Initialize the file history callback functions 4592654012fSReza Sabdar */ 4602654012fSReza Sabdar lbr_fhlog_call_backs_t * 4612654012fSReza Sabdar lbrlog_callbacks_init(void *cookie, path_hist_func_t log_pname_func, 4622654012fSReza Sabdar dir_hist_func_t log_dir_func, node_hist_func_t log_node_func) 4632654012fSReza Sabdar { 4642654012fSReza Sabdar lbr_fhlog_call_backs_t *p; 4652654012fSReza Sabdar 4662654012fSReza Sabdar p = ndmp_malloc(sizeof (lbr_fhlog_call_backs_t)); 4672654012fSReza Sabdar if (p == NULL) 4682654012fSReza Sabdar return (NULL); 4692654012fSReza Sabdar 4702654012fSReza Sabdar p->fh_cookie = cookie; 4712654012fSReza Sabdar p->fh_logpname = (func_t)log_pname_func; 4722654012fSReza Sabdar p->fh_log_dir = (func_t)log_dir_func; 4732654012fSReza Sabdar p->fh_log_node = (func_t)log_node_func; 4742654012fSReza Sabdar return (p); 4752654012fSReza Sabdar } 4762654012fSReza Sabdar 4772654012fSReza Sabdar /* 4782654012fSReza Sabdar * Cleanup the callbacks 4792654012fSReza Sabdar */ 4802654012fSReza Sabdar void 4812654012fSReza Sabdar lbrlog_callbacks_done(lbr_fhlog_call_backs_t *p) 4822654012fSReza Sabdar { 4832654012fSReza Sabdar if (p != NULL) 4842654012fSReza Sabdar (void) free((char *)p); 4852654012fSReza Sabdar } 4862654012fSReza Sabdar 4872654012fSReza Sabdar /* 4882654012fSReza Sabdar * Call back for file history directory info 4892654012fSReza Sabdar */ 4902654012fSReza Sabdar int 4912654012fSReza Sabdar tlm_log_fhdir(tlm_job_stats_t *job_stats, char *dir, struct stat64 *stp, 4922654012fSReza Sabdar fs_fhandle_t *fhp) 4932654012fSReza Sabdar { 4942654012fSReza Sabdar int rv; 4952654012fSReza Sabdar lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */ 4962654012fSReza Sabdar 4972654012fSReza Sabdar rv = 0; 4982654012fSReza Sabdar if (job_stats == NULL) { 4992654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhdir: jstat is NULL"); 5002654012fSReza Sabdar } else if (dir == NULL) { 5012654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhdir: dir is NULL"); 5022654012fSReza Sabdar } else if (stp == NULL) { 5032654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhdir: stp is NULL"); 5042654012fSReza Sabdar } else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks) 5052654012fSReza Sabdar == NULL) { 5062654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhdir: cbp is NULL"); 5072654012fSReza Sabdar } else if (cbp->fh_log_dir == NULL) { 5082654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhdir: callback is NULL"); 5092654012fSReza Sabdar } else 5102654012fSReza Sabdar rv = (*cbp->fh_log_dir)(cbp, dir, stp, fhp); 5112654012fSReza Sabdar 5122654012fSReza Sabdar return (rv); 5132654012fSReza Sabdar } 5142654012fSReza Sabdar 5152654012fSReza Sabdar /* 5162654012fSReza Sabdar * Call back for file history node info 5172654012fSReza Sabdar */ 5182654012fSReza Sabdar int 5192654012fSReza Sabdar tlm_log_fhnode(tlm_job_stats_t *job_stats, char *dir, char *file, 5202654012fSReza Sabdar struct stat64 *stp, u_longlong_t off) 5212654012fSReza Sabdar { 5222654012fSReza Sabdar int rv; 5232654012fSReza Sabdar lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */ 5242654012fSReza Sabdar 5252654012fSReza Sabdar rv = 0; 5262654012fSReza Sabdar if (job_stats == NULL) { 5272654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhnode: jstat is NULL"); 5282654012fSReza Sabdar } else if (dir == NULL) { 5292654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhnode: dir is NULL"); 5302654012fSReza Sabdar } else if (file == NULL) { 5312654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhnode: file is NULL"); 5322654012fSReza Sabdar } else if (stp == NULL) { 5332654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhnode: stp is NULL"); 5342654012fSReza Sabdar } else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks) 5352654012fSReza Sabdar == NULL) { 5362654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhnode: cbp is NULL"); 5372654012fSReza Sabdar } else if (cbp->fh_log_node == NULL) { 5382654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhnode: callback is NULL"); 5392654012fSReza Sabdar } else 5402654012fSReza Sabdar rv = (*cbp->fh_log_node)(cbp, dir, file, stp, off); 5412654012fSReza Sabdar 5422654012fSReza Sabdar return (rv); 5432654012fSReza Sabdar } 5442654012fSReza Sabdar 5452654012fSReza Sabdar /* 5462654012fSReza Sabdar * Call back for file history path info 5472654012fSReza Sabdar */ 5482654012fSReza Sabdar int 5492654012fSReza Sabdar tlm_log_fhpath_name(tlm_job_stats_t *job_stats, char *pathname, 5502654012fSReza Sabdar struct stat64 *stp, u_longlong_t off) 5512654012fSReza Sabdar { 5522654012fSReza Sabdar int rv; 5532654012fSReza Sabdar lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */ 5542654012fSReza Sabdar 5552654012fSReza Sabdar rv = 0; 5562654012fSReza Sabdar if (!job_stats) { 5572654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhpath_name: jstat is NULL"); 5582654012fSReza Sabdar } else if (!pathname) { 5592654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhpath_name: pathname is NULL"); 5602654012fSReza Sabdar } else if (!stp) { 5612654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhpath_name: stp is NULL"); 5622654012fSReza Sabdar } else if ((cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks) 5632654012fSReza Sabdar == 0) { 5642654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhpath_name: cbp is NULL"); 5652654012fSReza Sabdar } else if (!cbp->fh_logpname) { 5662654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "log_fhpath_name: callback is NULL"); 5672654012fSReza Sabdar } else 5682654012fSReza Sabdar rv = (*cbp->fh_logpname)(cbp, pathname, stp, off); 5692654012fSReza Sabdar 5702654012fSReza Sabdar return (rv); 5712654012fSReza Sabdar } 5722654012fSReza Sabdar 5732654012fSReza Sabdar 5742654012fSReza Sabdar /* 5752654012fSReza Sabdar * Log call back to report the entry recovery 5762654012fSReza Sabdar */ 5772654012fSReza Sabdar int 5782654012fSReza Sabdar tlm_entry_restored(tlm_job_stats_t *job_stats, char *name, int pos) 5792654012fSReza Sabdar { 5802654012fSReza Sabdar lbr_fhlog_call_backs_t *cbp; /* callbacks pointer */ 5812654012fSReza Sabdar 5822654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "name: \"%s\", pos: %d", name, pos); 5832654012fSReza Sabdar 5842654012fSReza Sabdar if (job_stats == NULL) { 5852654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "entry_restored: jstat is NULL"); 5862654012fSReza Sabdar return (0); 5872654012fSReza Sabdar } 5882654012fSReza Sabdar cbp = (lbr_fhlog_call_backs_t *)job_stats->js_callbacks; 5892654012fSReza Sabdar if (cbp == NULL) { 5902654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "entry_restored is NULL"); 5912654012fSReza Sabdar return (0); 5922654012fSReza Sabdar } 5932654012fSReza Sabdar return (*cbp->fh_logpname)(cbp, name, 0, (longlong_t)pos); 5942654012fSReza Sabdar } 5952654012fSReza Sabdar /* 5962654012fSReza Sabdar * NDMP support ends here. 5972654012fSReza Sabdar */ 5982654012fSReza Sabdar 5992654012fSReza Sabdar /* 6002654012fSReza Sabdar * Function: tlm_cat_path 6012654012fSReza Sabdar * Concatenates two path names 6022654012fSReza Sabdar * or directory name and file name 6032654012fSReza Sabdar * into a buffer passed by the caller. A slash 6042654012fSReza Sabdar * is inserted if required. Buffer is assumed 6052654012fSReza Sabdar * to hold PATH_MAX characters. 6062654012fSReza Sabdar * 6072654012fSReza Sabdar * Parameters: 6082654012fSReza Sabdar * char *buf - buffer to write new dir/name string 6092654012fSReza Sabdar * char *dir - directory name 6102654012fSReza Sabdar * char *name - file name 6112654012fSReza Sabdar * 6122654012fSReza Sabdar * Returns: 6132654012fSReza Sabdar * TRUE - No errors. buf contains the dir/name string 6142654012fSReza Sabdar * FALSE - Error. buf is not modified. 6152654012fSReza Sabdar */ 6162654012fSReza Sabdar boolean_t 6172654012fSReza Sabdar tlm_cat_path(char *buf, char *dir, char *name) 6182654012fSReza Sabdar { 6192654012fSReza Sabdar char *fmt; 6202654012fSReza Sabdar int dirlen = strlen(dir); 6212654012fSReza Sabdar int filelen = strlen(name); 6222654012fSReza Sabdar 6232654012fSReza Sabdar if ((dirlen + filelen + 1) >= PATH_MAX) { 6242654012fSReza Sabdar return (FALSE); 6252654012fSReza Sabdar } 6262654012fSReza Sabdar 6272654012fSReza Sabdar if (*dir == '\0' || *name == '\0' || dir[dirlen - 1] == '/' || 6282654012fSReza Sabdar *name == '/') { 6292654012fSReza Sabdar fmt = "%s%s"; 6302654012fSReza Sabdar } else { 6312654012fSReza Sabdar fmt = "%s/%s"; 6322654012fSReza Sabdar } 6332654012fSReza Sabdar 6342654012fSReza Sabdar /* check for ".../" and "/...." */ 6352654012fSReza Sabdar if ((dirlen > 0) && (dir[dirlen - 1] == '/') && (*name == '/')) 6362654012fSReza Sabdar name += strspn(name, "/"); 6372654012fSReza Sabdar 6382654012fSReza Sabdar /* LINTED variable format */ 6392654012fSReza Sabdar (void) snprintf(buf, TLM_MAX_PATH_NAME, fmt, dir, name); 6402654012fSReza Sabdar 6412654012fSReza Sabdar return (TRUE); 6422654012fSReza Sabdar } 6432654012fSReza Sabdar 6442654012fSReza Sabdar /* 6452654012fSReza Sabdar * Get the checkpoint (snapshot) creation time. 6462654012fSReza Sabdar * This is necessary to check for checkpoints not being stale. 6472654012fSReza Sabdar */ 6482654012fSReza Sabdar int 6492654012fSReza Sabdar tlm_get_chkpnt_time(char *path, int auto_checkpoint, time_t *tp, char *jname) 6502654012fSReza Sabdar { 6512654012fSReza Sabdar char volname[TLM_VOLNAME_MAX_LENGTH]; 6522654012fSReza Sabdar char chk_name[PATH_MAX]; 6532654012fSReza Sabdar char *cp_nm; 6542654012fSReza Sabdar 6552654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "path [%s] auto_checkpoint: %d", 6562654012fSReza Sabdar path, auto_checkpoint); 6572654012fSReza Sabdar 6582654012fSReza Sabdar if (path == NULL || *path == '\0' || tp == NULL) 6592654012fSReza Sabdar return (-1); 6602654012fSReza Sabdar 6612654012fSReza Sabdar if (get_zfsvolname(volname, TLM_VOLNAME_MAX_LENGTH, 6622654012fSReza Sabdar path) == -1) 6632654012fSReza Sabdar return (-1); 6642654012fSReza Sabdar 6652654012fSReza Sabdar if (auto_checkpoint) { 6662654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "volname [%s]", volname); 6678c4f9701SJanice Chang (void) snprintf(chk_name, PATH_MAX, "%s", jname); 6682654012fSReza Sabdar return (chkpnt_creationtime_bypattern(volname, chk_name, tp)); 6692654012fSReza Sabdar } 6702654012fSReza Sabdar cp_nm = strchr(volname, '@'); 6712654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "volname [%s] cp_nm [%s]", volname, cp_nm); 6722654012fSReza Sabdar 6732654012fSReza Sabdar return (chkpnt_creationtime_bypattern(volname, cp_nm, tp)); 6742654012fSReza Sabdar } 6752654012fSReza Sabdar 6762654012fSReza Sabdar /* 6772654012fSReza Sabdar * Release an array of pointers and the pointers themselves. 6782654012fSReza Sabdar */ 6792654012fSReza Sabdar void 6802654012fSReza Sabdar tlm_release_list(char **lpp) 6812654012fSReza Sabdar { 6822654012fSReza Sabdar char **save; 6832654012fSReza Sabdar 6842654012fSReza Sabdar if ((save = lpp) == 0) 6852654012fSReza Sabdar return; 6862654012fSReza Sabdar 6872654012fSReza Sabdar while (*lpp) 6882654012fSReza Sabdar free(*lpp++); 6892654012fSReza Sabdar 6902654012fSReza Sabdar free(save); 6912654012fSReza Sabdar } 6922654012fSReza Sabdar 6932654012fSReza Sabdar /* 6942654012fSReza Sabdar * Print the list of array of strings in the backup log 6952654012fSReza Sabdar */ 6962654012fSReza Sabdar void 6972654012fSReza Sabdar tlm_log_list(char *title, char **lpp) 6982654012fSReza Sabdar { 6992654012fSReza Sabdar int i; 7002654012fSReza Sabdar 7012654012fSReza Sabdar if (!lpp) 7022654012fSReza Sabdar return; 7032654012fSReza Sabdar 7042654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "%s:", title); 7052654012fSReza Sabdar 7062654012fSReza Sabdar for (i = 0; *lpp; lpp++, i++) 7072654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "%d: [%s]", i, *lpp); 7082654012fSReza Sabdar } 7092654012fSReza Sabdar 7102654012fSReza Sabdar /* 7112654012fSReza Sabdar * Insert the backup snapshot name into the path. 7122654012fSReza Sabdar * 7132654012fSReza Sabdar * Input: 7148c4f9701SJanice Chang * name: Original path name. 7152654012fSReza Sabdar * 7162654012fSReza Sabdar * Output: 7178c4f9701SJanice Chang * name: Original name modified to include a snapshot. 7182654012fSReza Sabdar * 7192654012fSReza Sabdar * Returns: 7208c4f9701SJanice Chang * Original name modified to include a snapshot. 7212654012fSReza Sabdar */ 7222654012fSReza Sabdar char * 7232654012fSReza Sabdar tlm_build_snapshot_name(char *name, char *sname, char *jname) 7242654012fSReza Sabdar { 7252654012fSReza Sabdar zfs_handle_t *zhp; 7262654012fSReza Sabdar char *rest; 727*40a5c998SMatthew Ahrens char volname[ZFS_MAX_DATASET_NAME_LEN]; 7282654012fSReza Sabdar char mountpoint[PATH_MAX]; 7292654012fSReza Sabdar 730*40a5c998SMatthew Ahrens if (get_zfsvolname(volname, ZFS_MAX_DATASET_NAME_LEN, name) == -1) 7312654012fSReza Sabdar goto notzfs; 7322654012fSReza Sabdar 7332654012fSReza Sabdar (void) mutex_lock(&zlib_mtx); 7342654012fSReza Sabdar if ((zlibh == NULL) || 7352654012fSReza Sabdar (zhp = zfs_open(zlibh, volname, ZFS_TYPE_DATASET)) == NULL) { 7362654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 7372654012fSReza Sabdar goto notzfs; 7382654012fSReza Sabdar } 7392654012fSReza Sabdar 7402654012fSReza Sabdar if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, mountpoint, PATH_MAX, NULL, 7412654012fSReza Sabdar NULL, 0, B_FALSE) != 0) { 7422654012fSReza Sabdar zfs_close(zhp); 7432654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 7442654012fSReza Sabdar goto notzfs; 7452654012fSReza Sabdar } 7462654012fSReza Sabdar 7472654012fSReza Sabdar zfs_close(zhp); 7482654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 7492654012fSReza Sabdar 7502654012fSReza Sabdar rest = name + strlen(mountpoint); 7518c4f9701SJanice Chang (void) snprintf(sname, TLM_MAX_PATH_NAME, "%s/%s/%s%s", mountpoint, 7522654012fSReza Sabdar TLM_SNAPSHOT_DIR, jname, rest); 7532654012fSReza Sabdar 7542654012fSReza Sabdar return (sname); 7552654012fSReza Sabdar 7562654012fSReza Sabdar notzfs: 7572654012fSReza Sabdar (void) strlcpy(sname, name, TLM_MAX_PATH_NAME); 7582654012fSReza Sabdar return (sname); 7592654012fSReza Sabdar } 7602654012fSReza Sabdar 7612654012fSReza Sabdar /* 7622654012fSReza Sabdar * Remove the checkpoint from a path name. 7632654012fSReza Sabdar * 7642654012fSReza Sabdar * Input: 7652654012fSReza Sabdar * name: Full pathname with checkpoint embeded. 7662654012fSReza Sabdar * 7672654012fSReza Sabdar * Output: 7682654012fSReza Sabdar * unchkp_name: real pathname with no checkpoint. 7692654012fSReza Sabdar * 7702654012fSReza Sabdar * Returns: 7712654012fSReza Sabdar * Pointer to the un-checkpointed path. 7722654012fSReza Sabdar */ 7732654012fSReza Sabdar char * 7742654012fSReza Sabdar tlm_remove_checkpoint(char *name, char *unchkp_name) 7752654012fSReza Sabdar { 7762654012fSReza Sabdar char *cp; 7772654012fSReza Sabdar int i; 7782654012fSReza Sabdar int plen; 7792654012fSReza Sabdar 7802654012fSReza Sabdar unchkp_name[0] = name[0]; 7812654012fSReza Sabdar plen = strlen(TLM_SNAPSHOT_PREFIX); 7822654012fSReza Sabdar for (i = 1; i <= TLM_VOLNAME_MAX_LENGTH + 1; i++) { 7832654012fSReza Sabdar switch (name[i]) { 7842654012fSReza Sabdar case '.': 7852654012fSReza Sabdar if (strncmp(&name[i], TLM_SNAPSHOT_PREFIX, 7862654012fSReza Sabdar plen) == 0) { 7872654012fSReza Sabdar unchkp_name[i] = '\0'; 7882654012fSReza Sabdar i += plen; 7892654012fSReza Sabdar if (name[i] == '\0') { 7902654012fSReza Sabdar /* 7912654012fSReza Sabdar * name == "/v1.chkpnt" 7922654012fSReza Sabdar */ 7932654012fSReza Sabdar return (unchkp_name); 7942654012fSReza Sabdar } 7952654012fSReza Sabdar if ((cp = strchr(&name[++i], '/')) != NULL) { 7962654012fSReza Sabdar (void) strlcat(unchkp_name, cp, 7972654012fSReza Sabdar TLM_VOLNAME_MAX_LENGTH + 1); 7982654012fSReza Sabdar } 7992654012fSReza Sabdar return (unchkp_name); 8002654012fSReza Sabdar } else { 8012654012fSReza Sabdar unchkp_name[i] = name[i]; 8022654012fSReza Sabdar } 8032654012fSReza Sabdar break; 8042654012fSReza Sabdar case '/': 8052654012fSReza Sabdar return (name); 8062654012fSReza Sabdar case 0: 8072654012fSReza Sabdar return (name); 8082654012fSReza Sabdar default: 8092654012fSReza Sabdar unchkp_name[i] = name[i]; 8102654012fSReza Sabdar break; 8112654012fSReza Sabdar } 8122654012fSReza Sabdar } 8132654012fSReza Sabdar return (name); 8142654012fSReza Sabdar } 8152654012fSReza Sabdar 8162654012fSReza Sabdar /* 8172654012fSReza Sabdar * see if we should exclude this file. 8182654012fSReza Sabdar */ 8192654012fSReza Sabdar boolean_t 8202654012fSReza Sabdar tlm_is_excluded(char *dir, char *name, char **excl_files) 8212654012fSReza Sabdar { 8222654012fSReza Sabdar int i; 8232654012fSReza Sabdar char full_name[TLM_MAX_PATH_NAME]; 8242654012fSReza Sabdar 8252654012fSReza Sabdar if (!dir || !name || !excl_files) 8262654012fSReza Sabdar return (FALSE); 8272654012fSReza Sabdar 8282654012fSReza Sabdar if (!tlm_cat_path(full_name, dir, name)) { 8292654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", 8302654012fSReza Sabdar dir, name); 8312654012fSReza Sabdar return (FALSE); 8322654012fSReza Sabdar } 8332654012fSReza Sabdar for (i = 0; excl_files[i] != 0; i++) { 8342654012fSReza Sabdar if (match(excl_files[i], full_name)) { 8352654012fSReza Sabdar return (TRUE); 8362654012fSReza Sabdar } 8372654012fSReza Sabdar } 8382654012fSReza Sabdar return (FALSE); 8392654012fSReza Sabdar } 8402654012fSReza Sabdar 8412654012fSReza Sabdar /* 8422654012fSReza Sabdar * Check if the path is too long 8432654012fSReza Sabdar */ 8442654012fSReza Sabdar boolean_t 8452654012fSReza Sabdar tlm_is_too_long(int checkpointed, char *dir, char *nm) 8462654012fSReza Sabdar { 8472654012fSReza Sabdar int nlen, tot; 8482654012fSReza Sabdar 8492654012fSReza Sabdar tot = 0; 8502654012fSReza Sabdar if (dir) 8512654012fSReza Sabdar tot += strlen(dir); 8522654012fSReza Sabdar if (checkpointed) 8532654012fSReza Sabdar tot += strlen(TLM_SNAPSHOT_DIR) + 1; 8542654012fSReza Sabdar if (nm) { 8552654012fSReza Sabdar if ((nlen = strlen(nm)) > 0) 8562654012fSReza Sabdar tot += nlen + 1; 8572654012fSReza Sabdar } 8582654012fSReza Sabdar return ((tot >= PATH_MAX) ? TRUE : FALSE); 8592654012fSReza Sabdar } 8602654012fSReza Sabdar 8612654012fSReza Sabdar /* 8622654012fSReza Sabdar * Get the data offset of inside the buffer 8632654012fSReza Sabdar */ 8642654012fSReza Sabdar longlong_t 8652654012fSReza Sabdar tlm_get_data_offset(tlm_cmd_t *lcmds) 8662654012fSReza Sabdar { 8672654012fSReza Sabdar if (!lcmds) 8682654012fSReza Sabdar return (0LL); 8692654012fSReza Sabdar 8702654012fSReza Sabdar return (lcmds->tc_buffers->tbs_offset); 8712654012fSReza Sabdar } 8722654012fSReza Sabdar 8732654012fSReza Sabdar /* 8742654012fSReza Sabdar * Enable the barcode capability on the library 8752654012fSReza Sabdar */ 8762654012fSReza Sabdar void 8772654012fSReza Sabdar tlm_enable_barcode(int l) 8782654012fSReza Sabdar { 8792654012fSReza Sabdar tlm_library_t *lp; 8802654012fSReza Sabdar 8812654012fSReza Sabdar if ((lp = tlm_library(l))) { 8822654012fSReza Sabdar lp->tl_capability_barcodes = TRUE; 8832654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 8842654012fSReza Sabdar "Barcode capability on library %d enabled.", l); 8852654012fSReza Sabdar } 8862654012fSReza Sabdar } 8872654012fSReza Sabdar 8882654012fSReza Sabdar /* 8892654012fSReza Sabdar * SASD SCSI support 8902654012fSReza Sabdar */ 8912654012fSReza Sabdar static scsi_adapter_t my_sa; 8922654012fSReza Sabdar static int sasd_drive_count = 0; 8932654012fSReza Sabdar static scsi_sasd_drive_t *scsi_sasd_drives[128]; 8942654012fSReza Sabdar 8952654012fSReza Sabdar /* 8962654012fSReza Sabdar * Count of SCSI devices 8972654012fSReza Sabdar */ 8982654012fSReza Sabdar int 8992654012fSReza Sabdar sasd_dev_count(void) 9002654012fSReza Sabdar { 9012654012fSReza Sabdar return (sasd_drive_count); 9022654012fSReza Sabdar } 9032654012fSReza Sabdar 9042654012fSReza Sabdar /* 9052654012fSReza Sabdar * Return the SCSI device name 9062654012fSReza Sabdar */ 9072654012fSReza Sabdar char * 9082654012fSReza Sabdar sasd_slink_name(scsi_link_t *slink) 9092654012fSReza Sabdar { 9102654012fSReza Sabdar int i; 9112654012fSReza Sabdar 9122654012fSReza Sabdar for (i = 0; i < sasd_drive_count; i++) { 9132654012fSReza Sabdar if (&scsi_sasd_drives[i]->ss_slink == slink) 9142654012fSReza Sabdar return (scsi_sasd_drives[i]->ss_sd.sd_name); 9152654012fSReza Sabdar } 9162654012fSReza Sabdar return (NULL); 9172654012fSReza Sabdar } 9182654012fSReza Sabdar 9192654012fSReza Sabdar /* 9202654012fSReza Sabdar * Return the SCSI drive structure 9212654012fSReza Sabdar */ 9222654012fSReza Sabdar sasd_drive_t * 9232654012fSReza Sabdar sasd_slink_drive(scsi_link_t *slink) 9242654012fSReza Sabdar { 9252654012fSReza Sabdar int i; 9262654012fSReza Sabdar 9272654012fSReza Sabdar for (i = 0; i < sasd_drive_count; i++) { 9282654012fSReza Sabdar if (&scsi_sasd_drives[i]->ss_slink == slink) 9292654012fSReza Sabdar return (&scsi_sasd_drives[i]->ss_sd); 9302654012fSReza Sabdar } 9312654012fSReza Sabdar return (NULL); 9322654012fSReza Sabdar } 9332654012fSReza Sabdar 9342654012fSReza Sabdar /* 9352654012fSReza Sabdar * Return the SCSI link pointer for the given index 9362654012fSReza Sabdar */ 9372654012fSReza Sabdar scsi_link_t * 9382654012fSReza Sabdar sasd_dev_slink(int entry) 9392654012fSReza Sabdar { 9402654012fSReza Sabdar scsi_link_t *rv; 9412654012fSReza Sabdar 9422654012fSReza Sabdar if (entry >= 0 && entry < sasd_drive_count) 9432654012fSReza Sabdar rv = &scsi_sasd_drives[entry]->ss_slink; 9442654012fSReza Sabdar else 9452654012fSReza Sabdar rv = NULL; 9462654012fSReza Sabdar 9472654012fSReza Sabdar return (rv); 9482654012fSReza Sabdar } 9492654012fSReza Sabdar 9502654012fSReza Sabdar /* 9512654012fSReza Sabdar * Return the SCSI drive for the given index 9522654012fSReza Sabdar */ 9532654012fSReza Sabdar sasd_drive_t * 9542654012fSReza Sabdar sasd_drive(int entry) 9552654012fSReza Sabdar { 9562654012fSReza Sabdar sasd_drive_t *rv; 9572654012fSReza Sabdar 9582654012fSReza Sabdar if (entry >= 0 && entry < sasd_drive_count) 9592654012fSReza Sabdar rv = &scsi_sasd_drives[entry]->ss_sd; 9602654012fSReza Sabdar else 9612654012fSReza Sabdar rv = NULL; 9622654012fSReza Sabdar 9632654012fSReza Sabdar return (rv); 9642654012fSReza Sabdar } 9652654012fSReza Sabdar 9662654012fSReza Sabdar /* 9672654012fSReza Sabdar * Attach the SCSI device by updating the structures 9682654012fSReza Sabdar */ 9692654012fSReza Sabdar void 9702654012fSReza Sabdar scsi_sasd_attach(scsi_adapter_t *sa, int sid, int lun, char *name, 9712654012fSReza Sabdar int type) 9722654012fSReza Sabdar { 9732654012fSReza Sabdar scsi_link_t *sl, *next; 9742654012fSReza Sabdar scsi_sasd_drive_t *ssd; 9752654012fSReza Sabdar 9762654012fSReza Sabdar ssd = ndmp_malloc(sizeof (scsi_sasd_drive_t)); 9772654012fSReza Sabdar if (ssd == NULL) 9782654012fSReza Sabdar return; 9792654012fSReza Sabdar 9802654012fSReza Sabdar scsi_sasd_drives[sasd_drive_count++] = ssd; 9812654012fSReza Sabdar 9822654012fSReza Sabdar switch (type) { 9832654012fSReza Sabdar case DTYPE_CHANGER: 9842654012fSReza Sabdar (void) snprintf(ssd->ss_sd.sd_name, 9852654012fSReza Sabdar sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_CHANGER_DIR, 9862654012fSReza Sabdar name); 9872654012fSReza Sabdar break; 9882654012fSReza Sabdar case DTYPE_SEQUENTIAL: 9892654012fSReza Sabdar (void) snprintf(ssd->ss_sd.sd_name, 9902654012fSReza Sabdar sizeof (ssd->ss_sd.sd_name), "%s/%s", SCSI_TAPE_DIR, name); 9912654012fSReza Sabdar break; 9922654012fSReza Sabdar } 9932654012fSReza Sabdar 9942654012fSReza Sabdar sl = &ssd->ss_slink; 9952654012fSReza Sabdar sl->sl_type = type; 9962654012fSReza Sabdar sl->sl_sa = sa; 9972654012fSReza Sabdar sl->sl_lun = lun; 9982654012fSReza Sabdar sl->sl_sid = sid; 9992654012fSReza Sabdar sl->sl_requested_max_active = 1; 10002654012fSReza Sabdar 10012654012fSReza Sabdar /* Insert slink */ 10022654012fSReza Sabdar next = sa->sa_link_head.sl_next; 10032654012fSReza Sabdar sa->sa_link_head.sl_next = sl; 10042654012fSReza Sabdar sl->sl_next = next; 10052654012fSReza Sabdar } 10062654012fSReza Sabdar 10072654012fSReza Sabdar /* 10082654012fSReza Sabdar * Go through the attached devices and detect the tape 10092654012fSReza Sabdar * and robot by checking the /dev entries 10102654012fSReza Sabdar */ 10112654012fSReza Sabdar int 10122654012fSReza Sabdar probe_scsi(void) 10132654012fSReza Sabdar { 10142654012fSReza Sabdar DIR *dirp; 10152654012fSReza Sabdar struct dirent *dp; 10162654012fSReza Sabdar scsi_adapter_t *sa = &my_sa; 10172654012fSReza Sabdar char *p; 10182654012fSReza Sabdar int lun = 0; 10192654012fSReza Sabdar int sid = 0; 10201e05b03fSJanice Chang char *drive_type; 10212654012fSReza Sabdar 10222654012fSReza Sabdar /* Initialize the scsi adapter link */ 10232654012fSReza Sabdar sa->sa_link_head.sl_next = &sa->sa_link_head; 10242654012fSReza Sabdar 10252654012fSReza Sabdar /* Scan for the changer */ 10262654012fSReza Sabdar dirp = opendir(SCSI_CHANGER_DIR); 10272654012fSReza Sabdar if (dirp == NULL) { 10282654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 10292654012fSReza Sabdar "Changer directory read error %s", SCSI_CHANGER_DIR); 10302654012fSReza Sabdar } else { 10312654012fSReza Sabdar while ((dp = readdir(dirp)) != NULL) { 10322654012fSReza Sabdar if ((strcmp(dp->d_name, ".") == 0) || 10332654012fSReza Sabdar (strcmp(dp->d_name, "..") == 0)) 10342654012fSReza Sabdar continue; 10352654012fSReza Sabdar 10362654012fSReza Sabdar if ((p = strchr(dp->d_name, 'd')) != NULL) { 10372654012fSReza Sabdar lun = atoi(++p); 10382654012fSReza Sabdar p = strchr(dp->d_name, 't'); 10392654012fSReza Sabdar sid = atoi(++p); 10402654012fSReza Sabdar } 10412654012fSReza Sabdar else 10422654012fSReza Sabdar sid = atoi(dp->d_name); 10432654012fSReza Sabdar 10442654012fSReza Sabdar scsi_sasd_attach(sa, 0, lun, dp->d_name, 10452654012fSReza Sabdar DTYPE_CHANGER); 10462654012fSReza Sabdar } 10472654012fSReza Sabdar (void) closedir(dirp); 10482654012fSReza Sabdar } 10492654012fSReza Sabdar 10502654012fSReza Sabdar /* Scan for tape drives */ 10512654012fSReza Sabdar dirp = opendir(SCSI_TAPE_DIR); 10522654012fSReza Sabdar if (dirp == NULL) { 10532654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 10542654012fSReza Sabdar "Tape directory read error %s", SCSI_TAPE_DIR); 10552654012fSReza Sabdar } else { 10561e05b03fSJanice Chang drive_type = ndmpd_get_prop(NDMP_DRIVE_TYPE); 10571e05b03fSJanice Chang 10581e05b03fSJanice Chang if ((strcasecmp(drive_type, "sysv") != 0) && 10591e05b03fSJanice Chang (strcasecmp(drive_type, "bsd") != 0)) { 10601e05b03fSJanice Chang NDMP_LOG(LOG_ERR, "Invalid ndmpd/drive-type value. " 10611e05b03fSJanice Chang "Valid values are 'sysv' and 'bsd'."); 10621e05b03fSJanice Chang return (-1); 10631e05b03fSJanice Chang } 10641e05b03fSJanice Chang 10652654012fSReza Sabdar while ((dp = readdir(dirp)) != NULL) { 10662654012fSReza Sabdar if ((strcmp(dp->d_name, ".") == 0) || 10672654012fSReza Sabdar (strcmp(dp->d_name, "..") == 0)) 10682654012fSReza Sabdar continue; 10692654012fSReza Sabdar 10702654012fSReza Sabdar /* Skip special modes */ 10711e05b03fSJanice Chang if (strpbrk(dp->d_name, "chlmu") != NULL) 10722654012fSReza Sabdar continue; 10732654012fSReza Sabdar 10742654012fSReza Sabdar /* Pick the non-rewind device */ 10752654012fSReza Sabdar if (strchr(dp->d_name, 'n') == NULL) 10762654012fSReza Sabdar continue; 10772654012fSReza Sabdar 10781e05b03fSJanice Chang if (strcasecmp(drive_type, "sysv") == 0) { 10791e05b03fSJanice Chang if (strchr(dp->d_name, 'b') != NULL) 10801e05b03fSJanice Chang continue; 10811e05b03fSJanice Chang } else if (strcasecmp(drive_type, "bsd") == 0) { 10821e05b03fSJanice Chang if (strchr(dp->d_name, 'b') == NULL) 10831e05b03fSJanice Chang continue; 10841e05b03fSJanice Chang } 10851e05b03fSJanice Chang 10862654012fSReza Sabdar sid = atoi(dp->d_name); 10872654012fSReza Sabdar 10882654012fSReza Sabdar /* 10892654012fSReza Sabdar * SCSI ID should match with the ID of the device 10902654012fSReza Sabdar * (will be checked by SCSI get elements page later) 10912654012fSReza Sabdar */ 10922654012fSReza Sabdar scsi_sasd_attach(sa, sid, 0, dp->d_name, 10932654012fSReza Sabdar DTYPE_SEQUENTIAL); 10942654012fSReza Sabdar } 10952654012fSReza Sabdar (void) closedir(dirp); 10962654012fSReza Sabdar } 10972654012fSReza Sabdar 10982654012fSReza Sabdar return (0); 10992654012fSReza Sabdar } 11002654012fSReza Sabdar 11012654012fSReza Sabdar /* 11022654012fSReza Sabdar * Get the SCSI device type (tape, robot) 11032654012fSReza Sabdar */ 11042654012fSReza Sabdar /*ARGSUSED*/ 11052654012fSReza Sabdar int 11062654012fSReza Sabdar scsi_get_devtype(char *adapter, int sid, int lun) 11072654012fSReza Sabdar { 11082654012fSReza Sabdar int rv; 11092654012fSReza Sabdar scsi_adapter_t *sa = &my_sa; 11102654012fSReza Sabdar scsi_link_t *sl, *sh; 11112654012fSReza Sabdar 11122654012fSReza Sabdar rv = -1; 11132654012fSReza Sabdar sh = &sa->sa_link_head; 11142654012fSReza Sabdar for (sl = sh->sl_next; sl != sh; sl = sl->sl_next) 11152654012fSReza Sabdar if (sl->sl_sid == sid && sl->sl_lun == lun) 11162654012fSReza Sabdar rv = sl->sl_type; 11172654012fSReza Sabdar 11182654012fSReza Sabdar return (rv); 11192654012fSReza Sabdar } 11202654012fSReza Sabdar 11212654012fSReza Sabdar 11222654012fSReza Sabdar /* 11232654012fSReza Sabdar * Check if the SCSI device exists 11242654012fSReza Sabdar */ 11252654012fSReza Sabdar /*ARGSUSED*/ 11262654012fSReza Sabdar int 11272654012fSReza Sabdar scsi_dev_exists(char *adapter, int sid, int lun) 11282654012fSReza Sabdar { 11292654012fSReza Sabdar scsi_adapter_t *sa = &my_sa; 11302654012fSReza Sabdar scsi_link_t *sl, *sh; 11312654012fSReza Sabdar 11322654012fSReza Sabdar sh = &sa->sa_link_head; 11332654012fSReza Sabdar for (sl = sh->sl_next; sl != sh; sl = sl->sl_next) 11342654012fSReza Sabdar if (sl->sl_sid == sid && sl->sl_lun == lun) 11352654012fSReza Sabdar return (1); 11362654012fSReza Sabdar return (0); 11372654012fSReza Sabdar } 11382654012fSReza Sabdar 11392654012fSReza Sabdar 11402654012fSReza Sabdar /* 11412654012fSReza Sabdar * Count of SCSI adapters 11422654012fSReza Sabdar */ 11432654012fSReza Sabdar int 11442654012fSReza Sabdar scsi_get_adapter_count(void) 11452654012fSReza Sabdar { 11462654012fSReza Sabdar /* Currently support one adapter only */ 11472654012fSReza Sabdar return (1); 11482654012fSReza Sabdar } 11492654012fSReza Sabdar 11502654012fSReza Sabdar /* 11512654012fSReza Sabdar * Return the SCSI adapter structure 11522654012fSReza Sabdar */ 11532654012fSReza Sabdar /*ARGSUSED*/ 11542654012fSReza Sabdar scsi_adapter_t * 11552654012fSReza Sabdar scsi_get_adapter(int adapter) 11562654012fSReza Sabdar { 11572654012fSReza Sabdar return (&my_sa); 11582654012fSReza Sabdar } 11592654012fSReza Sabdar 11602654012fSReza Sabdar /* 11612654012fSReza Sabdar * IOCTL wrapper with retries 11622654012fSReza Sabdar */ 11632654012fSReza Sabdar int 11642654012fSReza Sabdar tlm_ioctl(int fd, int cmd, void *data) 11652654012fSReza Sabdar { 11662654012fSReza Sabdar int retries = 0; 11672654012fSReza Sabdar 11682654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "tlm_ioctl fd %d cmd %d", fd, cmd); 11692654012fSReza Sabdar if (fd == 0 || data == NULL) 11702654012fSReza Sabdar return (EINVAL); 11712654012fSReza Sabdar 11722654012fSReza Sabdar do { 11732654012fSReza Sabdar if (ioctl(fd, cmd, data) == 0) 11742654012fSReza Sabdar break; 11752654012fSReza Sabdar 11762654012fSReza Sabdar if (errno != EIO && errno != 0) { 11772654012fSReza Sabdar NDMP_LOG(LOG_ERR, 11782654012fSReza Sabdar "Failed to send command to device: %m."); 11792654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "IOCTL error %d", errno); 11802654012fSReza Sabdar return (errno); 11812654012fSReza Sabdar } 11822654012fSReza Sabdar (void) sleep(1); 11832654012fSReza Sabdar } while (retries++ < MAXIORETRY); 11842654012fSReza Sabdar 11852654012fSReza Sabdar return (0); 11862654012fSReza Sabdar } 11872654012fSReza Sabdar 11882654012fSReza Sabdar /* 11892654012fSReza Sabdar * Checkpoint or snapshot calls 11902654012fSReza Sabdar */ 11912654012fSReza Sabdar 11922654012fSReza Sabdar /* 11932654012fSReza Sabdar * Get the snapshot creation time 11942654012fSReza Sabdar */ 11952654012fSReza Sabdar int 11962654012fSReza Sabdar chkpnt_creationtime_bypattern(char *volname, char *pattern, time_t *tp) 11972654012fSReza Sabdar { 11982654012fSReza Sabdar char chk_name[PATH_MAX]; 11992654012fSReza Sabdar zfs_handle_t *zhp; 12002654012fSReza Sabdar char *p; 12012654012fSReza Sabdar 12022654012fSReza Sabdar if (!volname || !*volname) 12032654012fSReza Sabdar return (-1); 12042654012fSReza Sabdar 12052654012fSReza Sabdar /* Should also return -1 if checkpoint not enabled */ 12062654012fSReza Sabdar 12072654012fSReza Sabdar /* Remove the leading slash */ 12082654012fSReza Sabdar p = volname; 12092654012fSReza Sabdar while (*p == '/') 12102654012fSReza Sabdar p++; 12112654012fSReza Sabdar 12122654012fSReza Sabdar (void) strlcpy(chk_name, p, PATH_MAX); 12132654012fSReza Sabdar (void) strlcat(chk_name, "@", PATH_MAX); 12142654012fSReza Sabdar (void) strlcat(chk_name, pattern, PATH_MAX); 12152654012fSReza Sabdar 12162654012fSReza Sabdar (void) mutex_lock(&zlib_mtx); 12172654012fSReza Sabdar if ((zhp = zfs_open(zlibh, chk_name, ZFS_TYPE_DATASET)) == NULL) { 12182654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "chkpnt_creationtime: open %s failed", 12192654012fSReza Sabdar chk_name); 12202654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 12212654012fSReza Sabdar return (-1); 12222654012fSReza Sabdar } 12232654012fSReza Sabdar 12242654012fSReza Sabdar *tp = zfs_prop_get_int(zhp, ZFS_PROP_CREATION); 12252654012fSReza Sabdar zfs_close(zhp); 12262654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 12272654012fSReza Sabdar 12282654012fSReza Sabdar return (0); 12292654012fSReza Sabdar } 12302654012fSReza Sabdar 12312654012fSReza Sabdar 12322654012fSReza Sabdar /* 12332654012fSReza Sabdar * Get the ZFS volume name out of the given path 12342654012fSReza Sabdar */ 12352654012fSReza Sabdar int 12362654012fSReza Sabdar get_zfsvolname(char *volname, int len, char *path) 12372654012fSReza Sabdar { 12382654012fSReza Sabdar struct stat64 stbuf; 12392654012fSReza Sabdar struct extmnttab ent; 12402654012fSReza Sabdar FILE *mntfp; 12412654012fSReza Sabdar int rv; 12422654012fSReza Sabdar 12432654012fSReza Sabdar *volname = '\0'; 12442654012fSReza Sabdar if (stat64(path, &stbuf) != 0) { 12452654012fSReza Sabdar return (-1); 12462654012fSReza Sabdar } 12472654012fSReza Sabdar 12482654012fSReza Sabdar if ((mntfp = fopen(MNTTAB, "r")) == NULL) { 12492654012fSReza Sabdar return (-1); 12502654012fSReza Sabdar } 12512654012fSReza Sabdar while ((rv = getextmntent(mntfp, &ent, 0)) == 0) { 12522654012fSReza Sabdar if (makedevice(ent.mnt_major, ent.mnt_minor) == 12532654012fSReza Sabdar stbuf.st_dev) 12542654012fSReza Sabdar break; 12552654012fSReza Sabdar } 12562654012fSReza Sabdar 12572654012fSReza Sabdar if (rv == 0 && 12582654012fSReza Sabdar strcmp(ent.mnt_fstype, MNTTYPE_ZFS) == 0) 12592654012fSReza Sabdar (void) strlcpy(volname, ent.mnt_special, len); 12602654012fSReza Sabdar else 12612654012fSReza Sabdar rv = -1; 12622654012fSReza Sabdar 12632654012fSReza Sabdar (void) fclose(mntfp); 12642654012fSReza Sabdar return (rv); 12652654012fSReza Sabdar } 12662654012fSReza Sabdar 12672654012fSReza Sabdar 12682654012fSReza Sabdar /* 12692654012fSReza Sabdar * Check if the volume type is snapshot volume 12702654012fSReza Sabdar */ 12712654012fSReza Sabdar boolean_t 12722654012fSReza Sabdar fs_is_chkpntvol(char *path) 12732654012fSReza Sabdar { 12742654012fSReza Sabdar zfs_handle_t *zhp; 1275*40a5c998SMatthew Ahrens char vol[ZFS_MAX_DATASET_NAME_LEN]; 12762654012fSReza Sabdar 12772654012fSReza Sabdar if (!path || !*path) 12782654012fSReza Sabdar return (FALSE); 12792654012fSReza Sabdar 12802654012fSReza Sabdar if (get_zfsvolname(vol, sizeof (vol), path) == -1) 12812654012fSReza Sabdar return (FALSE); 12822654012fSReza Sabdar 12832654012fSReza Sabdar (void) mutex_lock(&zlib_mtx); 12842654012fSReza Sabdar if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) { 12852654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 12862654012fSReza Sabdar return (FALSE); 12872654012fSReza Sabdar } 12882654012fSReza Sabdar 12892654012fSReza Sabdar if (zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) { 12902654012fSReza Sabdar zfs_close(zhp); 12912654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 12922654012fSReza Sabdar return (FALSE); 12932654012fSReza Sabdar } 12942654012fSReza Sabdar zfs_close(zhp); 12952654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 12962654012fSReza Sabdar 12972654012fSReza Sabdar return (TRUE); 12982654012fSReza Sabdar } 12992654012fSReza Sabdar 13002654012fSReza Sabdar /* 13012654012fSReza Sabdar * Check if the volume is capable of checkpoints 13022654012fSReza Sabdar */ 13032654012fSReza Sabdar boolean_t 13042654012fSReza Sabdar fs_is_chkpnt_enabled(char *path) 13052654012fSReza Sabdar { 13062654012fSReza Sabdar zfs_handle_t *zhp; 1307*40a5c998SMatthew Ahrens char vol[ZFS_MAX_DATASET_NAME_LEN]; 13082654012fSReza Sabdar 13092654012fSReza Sabdar if (!path || !*path) 13102654012fSReza Sabdar return (FALSE); 13112654012fSReza Sabdar 13122654012fSReza Sabdar (void) mutex_lock(&zlib_mtx); 13132654012fSReza Sabdar if (get_zfsvolname(vol, sizeof (vol), path) == -1) { 13142654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 13152654012fSReza Sabdar return (FALSE); 13162654012fSReza Sabdar } 13172654012fSReza Sabdar 13182654012fSReza Sabdar if ((zhp = zfs_open(zlibh, vol, ZFS_TYPE_DATASET)) == NULL) { 13192654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 13202654012fSReza Sabdar return (FALSE); 13212654012fSReza Sabdar } 13222654012fSReza Sabdar zfs_close(zhp); 13232654012fSReza Sabdar (void) mutex_unlock(&zlib_mtx); 13242654012fSReza Sabdar 13252654012fSReza Sabdar return (TRUE); 13262654012fSReza Sabdar } 13272654012fSReza Sabdar 13282654012fSReza Sabdar /* 13292654012fSReza Sabdar * Check if the volume is read-only 13302654012fSReza Sabdar */ 13312654012fSReza Sabdar boolean_t 13322654012fSReza Sabdar fs_is_rdonly(char *path) 13332654012fSReza Sabdar { 13342654012fSReza Sabdar return (fs_is_chkpntvol(path)); 13352654012fSReza Sabdar } 13362654012fSReza Sabdar 13372654012fSReza Sabdar /* 13382654012fSReza Sabdar * Min/max functions 13392654012fSReza Sabdar */ 13402654012fSReza Sabdar unsigned 1341*40a5c998SMatthew Ahrens min(unsigned a, unsigned b) 13422654012fSReza Sabdar { 13432654012fSReza Sabdar return (a < b ? a : b); 13442654012fSReza Sabdar } 13452654012fSReza Sabdar 13462654012fSReza Sabdar unsigned 1347*40a5c998SMatthew Ahrens max(unsigned a, unsigned b) 13482654012fSReza Sabdar { 13492654012fSReza Sabdar return (a > b ? a : b); 13502654012fSReza Sabdar } 13512654012fSReza Sabdar 13522654012fSReza Sabdar longlong_t 13532654012fSReza Sabdar llmin(longlong_t a, longlong_t b) 13542654012fSReza Sabdar { 13552654012fSReza Sabdar return (a < b ? a : b); 13562654012fSReza Sabdar } 1357