12654012fSReza Sabdar /* 25181c2afSReza Sabdar * 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 <stdio.h> 402654012fSReza Sabdar #include <limits.h> 412654012fSReza Sabdar #include <time.h> 422654012fSReza Sabdar #include <sys/stat.h> 432654012fSReza Sabdar #include <unistd.h> 442654012fSReza Sabdar #include <dirent.h> 452654012fSReza Sabdar #include <pthread.h> 462654012fSReza Sabdar #include <archives.h> 472654012fSReza Sabdar #include <tlm.h> 482654012fSReza Sabdar #include <sys/fs/zfs.h> 495181c2afSReza Sabdar #include <sys/mkdev.h> 502654012fSReza Sabdar #include <libzfs.h> 51b6b15642SReza Sabdar #include <libcmdutils.h> 52b6b15642SReza Sabdar #include <pwd.h> 53b6b15642SReza Sabdar #include <grp.h> 542654012fSReza Sabdar #include "tlm_proto.h" 552654012fSReza Sabdar 562654012fSReza Sabdar 572654012fSReza Sabdar static char *get_write_buffer(long size, 582654012fSReza Sabdar long *actual_size, 592654012fSReza Sabdar boolean_t zero, 602654012fSReza Sabdar tlm_cmd_t *); 612654012fSReza Sabdar static int output_acl_header(sec_attr_t *, 622654012fSReza Sabdar tlm_cmd_t *); 632654012fSReza Sabdar static int output_file_header(char *name, 642654012fSReza Sabdar char *link, 652654012fSReza Sabdar tlm_acls_t *, 662654012fSReza Sabdar int section, 672654012fSReza Sabdar tlm_cmd_t *); 682654012fSReza Sabdar static int output_xattr_header(char *fname, 692654012fSReza Sabdar char *aname, 702654012fSReza Sabdar int fd, 712654012fSReza Sabdar tlm_acls_t *, 722654012fSReza Sabdar int section, 732654012fSReza Sabdar tlm_cmd_t *); 742654012fSReza Sabdar 752654012fSReza Sabdar extern libzfs_handle_t *zlibh; 7689f9eb87SReza Sabdar extern mutex_t zlib_mtx; 772654012fSReza Sabdar 785181c2afSReza Sabdar #define S_ISPECIAL(a) (S_ISLNK(a) || S_ISFIFO(a) || S_ISBLK(a) || \ 795181c2afSReza Sabdar S_ISCHR(a)) 802654012fSReza Sabdar 812654012fSReza Sabdar /* 822654012fSReza Sabdar * output_mem 832654012fSReza Sabdar * 842654012fSReza Sabdar * Gets a IO write buffer and copies memory to the that. 852654012fSReza Sabdar */ 862654012fSReza Sabdar static void 872654012fSReza Sabdar output_mem(tlm_cmd_t *local_commands, char *mem, 882654012fSReza Sabdar int len) 892654012fSReza Sabdar { 902654012fSReza Sabdar long actual_size, rec_size; 912654012fSReza Sabdar char *rec; 922654012fSReza Sabdar 932654012fSReza Sabdar while (len > 0) { 942654012fSReza Sabdar rec = get_write_buffer(len, &actual_size, 952654012fSReza Sabdar FALSE, local_commands); 962654012fSReza Sabdar rec_size = min(actual_size, len); 972654012fSReza Sabdar (void) memcpy(rec, mem, rec_size); 982654012fSReza Sabdar mem += rec_size; 992654012fSReza Sabdar len -= rec_size; 1002654012fSReza Sabdar } 1012654012fSReza Sabdar } 1022654012fSReza Sabdar 1032654012fSReza Sabdar /* 1042654012fSReza Sabdar * tlm_output_dir 1052654012fSReza Sabdar * 1062654012fSReza Sabdar * Put the directory information into the output buffers. 1072654012fSReza Sabdar */ 1082654012fSReza Sabdar int 1092654012fSReza Sabdar tlm_output_dir(char *name, tlm_acls_t *tlm_acls, 1102654012fSReza Sabdar tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats) 1112654012fSReza Sabdar { 1122654012fSReza Sabdar u_longlong_t pos; 1132654012fSReza Sabdar 1142654012fSReza Sabdar /* 1152654012fSReza Sabdar * Send the node or path history of the directory itself. 1162654012fSReza Sabdar */ 1172654012fSReza Sabdar pos = tlm_get_data_offset(local_commands); 1182654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "pos: %10lld [%s]", pos, name); 1192654012fSReza Sabdar (void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos); 1202654012fSReza Sabdar (void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos); 1212654012fSReza Sabdar /* fhdir_cb is handled in ndmpd_tar3.c */ 1222654012fSReza Sabdar 1232654012fSReza Sabdar (void) output_acl_header(&tlm_acls->acl_info, 1242654012fSReza Sabdar local_commands); 1252654012fSReza Sabdar (void) output_file_header(name, "", tlm_acls, 0, 1262654012fSReza Sabdar local_commands); 1272654012fSReza Sabdar 1282654012fSReza Sabdar return (0); 1292654012fSReza Sabdar } 1302654012fSReza Sabdar 1312654012fSReza Sabdar /* 1322654012fSReza Sabdar * tar_putdir 1332654012fSReza Sabdar * 1342654012fSReza Sabdar * Main dir backup function for tar 1352654012fSReza Sabdar */ 1362654012fSReza Sabdar int 1372654012fSReza Sabdar tar_putdir(char *name, tlm_acls_t *tlm_acls, 1382654012fSReza Sabdar tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats) 1392654012fSReza Sabdar { 1402654012fSReza Sabdar int rv; 1412654012fSReza Sabdar 1422654012fSReza Sabdar rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats); 1432654012fSReza Sabdar return (rv < 0 ? rv : 0); 1442654012fSReza Sabdar } 1452654012fSReza Sabdar 1462654012fSReza Sabdar /* 1472654012fSReza Sabdar * output_acl_header 1482654012fSReza Sabdar * 1492654012fSReza Sabdar * output the ACL header record and data 1502654012fSReza Sabdar */ 1512654012fSReza Sabdar static int 1522654012fSReza Sabdar output_acl_header(sec_attr_t *acl_info, 1532654012fSReza Sabdar tlm_cmd_t *local_commands) 1542654012fSReza Sabdar { 1552654012fSReza Sabdar long actual_size; 1562654012fSReza Sabdar tlm_tar_hdr_t *tar_hdr; 1572654012fSReza Sabdar long acl_size; 1582654012fSReza Sabdar 1592654012fSReza Sabdar if ((acl_info == NULL) || (*acl_info->attr_info == '\0')) 1602654012fSReza Sabdar return (0); 1612654012fSReza Sabdar 1622654012fSReza Sabdar tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, 1632654012fSReza Sabdar &actual_size, TRUE, local_commands); 1642654012fSReza Sabdar if (!tar_hdr) 1652654012fSReza Sabdar return (0); 1662654012fSReza Sabdar 1672654012fSReza Sabdar tar_hdr->th_linkflag = LF_ACL; 1682654012fSReza Sabdar acl_info->attr_type = UFSD_ACL; 1692654012fSReza Sabdar (void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len), 1702654012fSReza Sabdar "%06o", strlen(acl_info->attr_info)); 1712654012fSReza Sabdar 1722654012fSReza Sabdar acl_size = sizeof (*acl_info); 1732654012fSReza Sabdar (void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE); 1742654012fSReza Sabdar (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", 1752654012fSReza Sabdar acl_size); 1762654012fSReza Sabdar (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", 1772654012fSReza Sabdar 0444); 1782654012fSReza Sabdar (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0); 1792654012fSReza Sabdar (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0); 1802654012fSReza Sabdar (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), 1812654012fSReza Sabdar "%011o ", 0); 1822654012fSReza Sabdar (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, 1832654012fSReza Sabdar sizeof (tar_hdr->th_magic)); 1842654012fSReza Sabdar 1852654012fSReza Sabdar tlm_build_header_checksum(tar_hdr); 1862654012fSReza Sabdar 1872654012fSReza Sabdar (void) output_mem(local_commands, (void *)acl_info, acl_size); 1882654012fSReza Sabdar return (0); 1892654012fSReza Sabdar } 1902654012fSReza Sabdar 1912654012fSReza Sabdar /* 1922654012fSReza Sabdar * output_humongus_header 1932654012fSReza Sabdar * 1942654012fSReza Sabdar * output a special header record for HUGE files 1952654012fSReza Sabdar * output is: 1) a TAR "HUGE" header redord 1962654012fSReza Sabdar * 2) a "file" of size, name 1972654012fSReza Sabdar */ 1982654012fSReza Sabdar static int 1992654012fSReza Sabdar output_humongus_header(char *fullname, longlong_t file_size, 2002654012fSReza Sabdar tlm_cmd_t *local_commands) 2012654012fSReza Sabdar { 2022654012fSReza Sabdar char *buf; 2032654012fSReza Sabdar int len; 2042654012fSReza Sabdar long actual_size; 2052654012fSReza Sabdar tlm_tar_hdr_t *tar_hdr; 2062654012fSReza Sabdar 2072654012fSReza Sabdar /* 2082654012fSReza Sabdar * buf will contain: "%llu %s": 2092654012fSReza Sabdar * - 20 is the maximum length of 'ulong_tlong' decimal notation. 2102654012fSReza Sabdar * - The first '1' is for the ' ' between the "%llu" and the fullname. 2112654012fSReza Sabdar * - The last '1' is for the null-terminator of fullname. 2122654012fSReza Sabdar */ 2132654012fSReza Sabdar len = 20 + 1 + strlen(fullname) + 1; 2142654012fSReza Sabdar 2152654012fSReza Sabdar if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL) 2162654012fSReza Sabdar return (-1); 2172654012fSReza Sabdar 2182654012fSReza Sabdar tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, 2192654012fSReza Sabdar &actual_size, TRUE, local_commands); 2202654012fSReza Sabdar if (!tar_hdr) { 2212654012fSReza Sabdar free(buf); 2222654012fSReza Sabdar return (0); 2232654012fSReza Sabdar } 2242654012fSReza Sabdar 2252654012fSReza Sabdar tar_hdr->th_linkflag = LF_HUMONGUS; 2262654012fSReza Sabdar (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", 2272654012fSReza Sabdar len); 2282654012fSReza Sabdar tlm_build_header_checksum(tar_hdr); 2292654012fSReza Sabdar (void) snprintf(buf, len, "%lld %s", file_size, fullname); 2302654012fSReza Sabdar (void) output_mem(local_commands, buf, len); 2312654012fSReza Sabdar 2322654012fSReza Sabdar free(buf); 2332654012fSReza Sabdar return (0); 2342654012fSReza Sabdar } 2352654012fSReza Sabdar 2362654012fSReza Sabdar 2372654012fSReza Sabdar /* 2382654012fSReza Sabdar * output_xattr_header 2392654012fSReza Sabdar * 2402654012fSReza Sabdar * output the TAR header record for extended attributes 2412654012fSReza Sabdar */ 2422654012fSReza Sabdar static int 2432654012fSReza Sabdar output_xattr_header(char *fname, char *aname, int fd, 2442654012fSReza Sabdar tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands) 2452654012fSReza Sabdar { 2462654012fSReza Sabdar struct stat64 *attr = &tlm_acls->acl_attr; 2472654012fSReza Sabdar struct xattr_hdr *xhdr; 2482654012fSReza Sabdar struct xattr_buf *xbuf; 2492654012fSReza Sabdar tlm_tar_hdr_t *tar_hdr; 2502654012fSReza Sabdar long actual_size; 2512654012fSReza Sabdar char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME); 2522654012fSReza Sabdar int hsize; 2532654012fSReza Sabdar int comlen; 2542654012fSReza Sabdar int namesz; 2552654012fSReza Sabdar 2562654012fSReza Sabdar if (section_name == NULL) 2572654012fSReza Sabdar return (-TLM_NO_SCRATCH_SPACE); 2582654012fSReza Sabdar 2592654012fSReza Sabdar if (fstat64(fd, attr) == -1) { 2602654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "output_file_header stat failed."); 2612654012fSReza Sabdar free(section_name); 2622654012fSReza Sabdar return (-TLM_OPEN_ERR); 2632654012fSReza Sabdar } 2642654012fSReza Sabdar 2652654012fSReza Sabdar /* 2662654012fSReza Sabdar * if the file has to go out in sections, 2672654012fSReza Sabdar * we must mung the name. 2682654012fSReza Sabdar */ 2692654012fSReza Sabdar if (section == 0) { 2702654012fSReza Sabdar (void) snprintf(section_name, TLM_MAX_PATH_NAME, 2712654012fSReza Sabdar "/dev/null/%s.hdr", aname); 2722654012fSReza Sabdar } else { 2732654012fSReza Sabdar (void) snprintf(section_name, 2742654012fSReza Sabdar TLM_MAX_PATH_NAME, "%s.%03d", aname, section); 2752654012fSReza Sabdar } 2762654012fSReza Sabdar namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */ 2772654012fSReza Sabdar hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf); 2782654012fSReza Sabdar comlen = namesz + sizeof (struct xattr_buf); 2792654012fSReza Sabdar 2802654012fSReza Sabdar tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, 2812654012fSReza Sabdar &actual_size, TRUE, local_commands); 2822654012fSReza Sabdar if (!tar_hdr) { 2832654012fSReza Sabdar free(section_name); 2842654012fSReza Sabdar return (0); 2852654012fSReza Sabdar } 2862654012fSReza Sabdar 2872654012fSReza Sabdar (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE); 2882654012fSReza Sabdar 2892654012fSReza Sabdar tar_hdr->th_linkflag = LF_XATTR; 2902654012fSReza Sabdar (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", 2912654012fSReza Sabdar hsize); 2922654012fSReza Sabdar (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", 2932654012fSReza Sabdar attr->st_mode & 07777); 2942654012fSReza Sabdar (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 2952654012fSReza Sabdar attr->st_uid); 2962654012fSReza Sabdar (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 2972654012fSReza Sabdar attr->st_gid); 2982654012fSReza Sabdar (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", 2992654012fSReza Sabdar attr->st_mtime); 3002654012fSReza Sabdar (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, 3012654012fSReza Sabdar sizeof (tar_hdr->th_magic)); 3022654012fSReza Sabdar 303b6b15642SReza Sabdar NDMP_LOG(LOG_DEBUG, "xattr_hdr: %s size %d mode %06o uid %d gid %d", 304b6b15642SReza Sabdar aname, hsize, attr->st_mode & 07777, attr->st_uid, attr->st_gid); 305b6b15642SReza Sabdar 3062654012fSReza Sabdar tlm_build_header_checksum(tar_hdr); 3072654012fSReza Sabdar 3082654012fSReza Sabdar xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE, 3092654012fSReza Sabdar &actual_size, TRUE, local_commands); 3102654012fSReza Sabdar if (!xhdr) { 3112654012fSReza Sabdar free(section_name); 3122654012fSReza Sabdar return (0); 3132654012fSReza Sabdar } 3142654012fSReza Sabdar 3152654012fSReza Sabdar (void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s", 3162654012fSReza Sabdar XATTR_ARCH_VERS); 3172654012fSReza Sabdar (void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d", 3182654012fSReza Sabdar sizeof (xhdr->h_size) - 1, hsize); 3192654012fSReza Sabdar (void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len), 3202654012fSReza Sabdar "%0*d", sizeof (xhdr->h_component_len) - 1, comlen); 3212654012fSReza Sabdar (void) snprintf(xhdr->h_link_component_len, 3222654012fSReza Sabdar sizeof (xhdr->h_link_component_len), "%0*d", 3232654012fSReza Sabdar sizeof (xhdr->h_link_component_len) - 1, 0); 3242654012fSReza Sabdar 3252654012fSReza Sabdar xbuf = (struct xattr_buf *)(((caddr_t)xhdr) + 3262654012fSReza Sabdar sizeof (struct xattr_hdr)); 3272654012fSReza Sabdar (void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d", 3282654012fSReza Sabdar sizeof (xbuf->h_namesz) - 1, namesz); 3292654012fSReza Sabdar 3302654012fSReza Sabdar /* No support for links in extended attributes */ 3312654012fSReza Sabdar xbuf->h_typeflag = LF_NORMAL; 3322654012fSReza Sabdar 3332654012fSReza Sabdar (void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE); 3342654012fSReza Sabdar (void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname, 3352654012fSReza Sabdar TLM_NAME_SIZE); 3362654012fSReza Sabdar 3372654012fSReza Sabdar free(section_name); 3382654012fSReza Sabdar return (0); 3392654012fSReza Sabdar } 3402654012fSReza Sabdar 3412654012fSReza Sabdar 3422654012fSReza Sabdar /* 3432654012fSReza Sabdar * output_file_header 3442654012fSReza Sabdar * 3452654012fSReza Sabdar * output the TAR header record 3462654012fSReza Sabdar */ 3472654012fSReza Sabdar static int 3482654012fSReza Sabdar output_file_header(char *name, char *link, 3492654012fSReza Sabdar tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands) 3502654012fSReza Sabdar { 3512654012fSReza Sabdar static longlong_t file_count = 0; 3522654012fSReza Sabdar struct stat64 *attr = &tlm_acls->acl_attr; 3532654012fSReza Sabdar tlm_tar_hdr_t *tar_hdr; 3542654012fSReza Sabdar long actual_size; 3552654012fSReza Sabdar boolean_t long_name = FALSE; 3562654012fSReza Sabdar boolean_t long_link = FALSE; 3572654012fSReza Sabdar char *section_name = ndmp_malloc(TLM_MAX_PATH_NAME); 3582654012fSReza Sabdar int nmlen, lnklen; 359b6b15642SReza Sabdar uid_t uid; 360b6b15642SReza Sabdar gid_t gid; 361b6b15642SReza Sabdar char *uname = ""; 362b6b15642SReza Sabdar char *gname = ""; 363b6b15642SReza Sabdar struct passwd *pwd; 364b6b15642SReza Sabdar struct group *grp; 3652654012fSReza Sabdar 3662654012fSReza Sabdar if (section_name == NULL) 3672654012fSReza Sabdar return (-TLM_NO_SCRATCH_SPACE); 3682654012fSReza Sabdar 3692654012fSReza Sabdar /* 3702654012fSReza Sabdar * if the file has to go out in sections, 3712654012fSReza Sabdar * we must mung the name. 3722654012fSReza Sabdar */ 3732654012fSReza Sabdar if (section == 0) { 3742654012fSReza Sabdar (void) strlcpy(section_name, name, TLM_MAX_PATH_NAME); 3752654012fSReza Sabdar } else { 3762654012fSReza Sabdar (void) snprintf(section_name, 3772654012fSReza Sabdar TLM_MAX_PATH_NAME, "%s.%03d", name, section); 3782654012fSReza Sabdar } 3792654012fSReza Sabdar 380b6b15642SReza Sabdar if ((pwd = getpwuid(attr->st_uid)) != NULL) 381b6b15642SReza Sabdar uname = pwd->pw_name; 382b6b15642SReza Sabdar if ((grp = getgrgid(attr->st_gid)) != NULL) 383b6b15642SReza Sabdar gname = grp->gr_name; 384b6b15642SReza Sabdar 385b6b15642SReza Sabdar if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR) 386b6b15642SReza Sabdar uid = UID_NOBODY; 387b6b15642SReza Sabdar if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR) 388b6b15642SReza Sabdar gid = GID_NOBODY; 389b6b15642SReza Sabdar 3902654012fSReza Sabdar nmlen = strlen(section_name); 3912654012fSReza Sabdar if (nmlen >= NAMSIZ) { 3922654012fSReza Sabdar /* 3932654012fSReza Sabdar * file name is too big, it must go out 3942654012fSReza Sabdar * in its own data file 3952654012fSReza Sabdar */ 3962654012fSReza Sabdar tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, 3972654012fSReza Sabdar &actual_size, TRUE, local_commands); 3982654012fSReza Sabdar if (!tar_hdr) { 3992654012fSReza Sabdar free(section_name); 4002654012fSReza Sabdar return (0); 4012654012fSReza Sabdar } 4022654012fSReza Sabdar (void) snprintf(tar_hdr->th_name, 4032654012fSReza Sabdar sizeof (tar_hdr->th_name), 4042654012fSReza Sabdar "%s%08qd.fil", 4052654012fSReza Sabdar LONGNAME_PREFIX, 4062654012fSReza Sabdar file_count++); 4072654012fSReza Sabdar 4082654012fSReza Sabdar tar_hdr->th_linkflag = LF_LONGNAME; 4092654012fSReza Sabdar (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), 4102654012fSReza Sabdar "%011o ", nmlen); 4112654012fSReza Sabdar (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), 4122654012fSReza Sabdar "%06o ", attr->st_mode & 07777); 4132654012fSReza Sabdar (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), 414b6b15642SReza Sabdar "%06o ", uid); 4152654012fSReza Sabdar (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), 416b6b15642SReza Sabdar "%06o ", gid); 417b6b15642SReza Sabdar (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), 418b6b15642SReza Sabdar "%.31s", uname); 419b6b15642SReza Sabdar (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), 420b6b15642SReza Sabdar "%.31s", gname); 4212654012fSReza Sabdar (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), 4222654012fSReza Sabdar "%011o ", attr->st_mtime); 4232654012fSReza Sabdar (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, 4242654012fSReza Sabdar sizeof (tar_hdr->th_magic)); 4252654012fSReza Sabdar 4262654012fSReza Sabdar tlm_build_header_checksum(tar_hdr); 4272654012fSReza Sabdar 4282654012fSReza Sabdar (void) output_mem(local_commands, 4292654012fSReza Sabdar (void *)section_name, nmlen); 4302654012fSReza Sabdar long_name = TRUE; 4312654012fSReza Sabdar } 4322654012fSReza Sabdar 4332654012fSReza Sabdar lnklen = strlen(link); 4342654012fSReza Sabdar if (lnklen >= NAMSIZ) { 4352654012fSReza Sabdar /* 4362654012fSReza Sabdar * link name is too big, it must go out 4372654012fSReza Sabdar * in its own data file 4382654012fSReza Sabdar */ 4392654012fSReza Sabdar tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, 4402654012fSReza Sabdar &actual_size, TRUE, local_commands); 4412654012fSReza Sabdar if (!tar_hdr) { 4422654012fSReza Sabdar free(section_name); 4432654012fSReza Sabdar return (0); 4442654012fSReza Sabdar } 4452654012fSReza Sabdar (void) snprintf(tar_hdr->th_linkname, 4462654012fSReza Sabdar sizeof (tar_hdr->th_name), 4472654012fSReza Sabdar "%s%08qd.slk", 4482654012fSReza Sabdar LONGNAME_PREFIX, 4492654012fSReza Sabdar file_count++); 4502654012fSReza Sabdar 4512654012fSReza Sabdar tar_hdr->th_linkflag = LF_LONGLINK; 4522654012fSReza Sabdar (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), 4532654012fSReza Sabdar "%011o ", lnklen); 4542654012fSReza Sabdar (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), 4552654012fSReza Sabdar "%06o ", attr->st_mode & 07777); 4562654012fSReza Sabdar (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), 457b6b15642SReza Sabdar "%06o ", uid); 4582654012fSReza Sabdar (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), 459b6b15642SReza Sabdar "%06o ", gid); 460b6b15642SReza Sabdar (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), 461b6b15642SReza Sabdar "%.31s", uname); 462b6b15642SReza Sabdar (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), 463b6b15642SReza Sabdar "%.31s", gname); 4642654012fSReza Sabdar (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), 4652654012fSReza Sabdar "%011o ", attr->st_mtime); 4662654012fSReza Sabdar (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, 4672654012fSReza Sabdar sizeof (tar_hdr->th_magic)); 4682654012fSReza Sabdar 4692654012fSReza Sabdar tlm_build_header_checksum(tar_hdr); 4702654012fSReza Sabdar 4712654012fSReza Sabdar (void) output_mem(local_commands, (void *)link, 4722654012fSReza Sabdar lnklen); 4732654012fSReza Sabdar long_link = TRUE; 4742654012fSReza Sabdar } 4752654012fSReza Sabdar tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE, 4762654012fSReza Sabdar &actual_size, TRUE, local_commands); 4772654012fSReza Sabdar if (!tar_hdr) { 4782654012fSReza Sabdar free(section_name); 4792654012fSReza Sabdar return (0); 4802654012fSReza Sabdar } 4812654012fSReza Sabdar if (long_name) { 4822654012fSReza Sabdar (void) snprintf(tar_hdr->th_name, 4832654012fSReza Sabdar sizeof (tar_hdr->th_name), 4842654012fSReza Sabdar "%s%08qd.fil", 4852654012fSReza Sabdar LONGNAME_PREFIX, 4862654012fSReza Sabdar file_count++); 4872654012fSReza Sabdar } else { 4882654012fSReza Sabdar (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE); 4892654012fSReza Sabdar } 4902654012fSReza Sabdar 4912654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "long_link: %s [%s]", long_link ? "TRUE" : "FALSE", 4922654012fSReza Sabdar link); 4932654012fSReza Sabdar 4942654012fSReza Sabdar if (long_link) { 4952654012fSReza Sabdar (void) snprintf(tar_hdr->th_linkname, 4962654012fSReza Sabdar sizeof (tar_hdr->th_name), 4972654012fSReza Sabdar "%s%08qd.slk", 4982654012fSReza Sabdar LONGNAME_PREFIX, 4992654012fSReza Sabdar file_count++); 5002654012fSReza Sabdar } else { 5012654012fSReza Sabdar (void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE); 5022654012fSReza Sabdar } 5035181c2afSReza Sabdar switch (attr->st_mode & S_IFMT) { 5045181c2afSReza Sabdar case S_IFDIR: 5052654012fSReza Sabdar tar_hdr->th_linkflag = LF_DIR; 5065181c2afSReza Sabdar break; 5075181c2afSReza Sabdar case S_IFIFO: 5082654012fSReza Sabdar tar_hdr->th_linkflag = LF_FIFO; 5095181c2afSReza Sabdar break; 5105181c2afSReza Sabdar case S_IFBLK: 5115181c2afSReza Sabdar case S_IFCHR: 5125181c2afSReza Sabdar if (S_ISBLK(attr->st_mode)) 5135181c2afSReza Sabdar tar_hdr->th_linkflag = LF_BLK; 5145181c2afSReza Sabdar else 5155181c2afSReza Sabdar tar_hdr->th_linkflag = LF_CHR; 5165181c2afSReza Sabdar (void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor, 5175181c2afSReza Sabdar sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ", 5185181c2afSReza Sabdar major(attr->st_rdev)); 5195181c2afSReza Sabdar (void) snprintf(tar_hdr->th_shared.th_dev.th_devminor, 5205181c2afSReza Sabdar sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ", 5215181c2afSReza Sabdar minor(attr->st_rdev)); 5225181c2afSReza Sabdar break; 5235181c2afSReza Sabdar default: 5245181c2afSReza Sabdar if (attr->st_nlink > 1) { 5252654012fSReza Sabdar /* mark file with hardlink LF_LINK */ 5262654012fSReza Sabdar tar_hdr->th_linkflag = LF_LINK; 5272654012fSReza Sabdar (void) snprintf(tar_hdr->th_shared.th_hlink_ino, 5282654012fSReza Sabdar sizeof (tar_hdr->th_shared.th_hlink_ino), 5297bc22e45SReza Sabdar "%011llo ", attr->st_ino); 5302654012fSReza Sabdar } else { 5315181c2afSReza Sabdar tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL : 5325181c2afSReza Sabdar LF_SYMLINK; 5335181c2afSReza Sabdar NDMP_LOG(LOG_DEBUG, "linkflag: '%c'", 5345181c2afSReza Sabdar tar_hdr->th_linkflag); 5355181c2afSReza Sabdar } 5362654012fSReza Sabdar } 5372654012fSReza Sabdar (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ", 5382654012fSReza Sabdar (long)attr->st_size); 5392654012fSReza Sabdar (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ", 5402654012fSReza Sabdar attr->st_mode & 07777); 5412654012fSReza Sabdar (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 542b6b15642SReza Sabdar uid); 5432654012fSReza Sabdar (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 544b6b15642SReza Sabdar gid); 545b6b15642SReza Sabdar (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s", 546b6b15642SReza Sabdar uname); 547b6b15642SReza Sabdar (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s", 548b6b15642SReza Sabdar gname); 5492654012fSReza Sabdar (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ", 5502654012fSReza Sabdar attr->st_mtime); 5512654012fSReza Sabdar (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC, 5522654012fSReza Sabdar sizeof (tar_hdr->th_magic)); 5532654012fSReza Sabdar 5542654012fSReza Sabdar tlm_build_header_checksum(tar_hdr); 5552654012fSReza Sabdar if (long_name || long_link) { 5562654012fSReza Sabdar if (file_count > 99999990) { 5572654012fSReza Sabdar file_count = 0; 5582654012fSReza Sabdar } 5592654012fSReza Sabdar } 5602654012fSReza Sabdar free(section_name); 5612654012fSReza Sabdar return (0); 5622654012fSReza Sabdar } 5632654012fSReza Sabdar 5642654012fSReza Sabdar 5652654012fSReza Sabdar /* 5662654012fSReza Sabdar * tlm_readlink 5672654012fSReza Sabdar * 5682654012fSReza Sabdar * Read where the softlink points to. Read the link in the checkpointed 5692654012fSReza Sabdar * path if the backup is being done on a checkpointed file system. 5702654012fSReza Sabdar */ 5712654012fSReza Sabdar static int 5722654012fSReza Sabdar tlm_readlink(char *nm, char *snap, char *buf, int bufsize) 5732654012fSReza Sabdar { 5742654012fSReza Sabdar int len; 5752654012fSReza Sabdar 5762654012fSReza Sabdar if ((len = readlink(snap, buf, bufsize)) >= 0) { 5772654012fSReza Sabdar /* 5782654012fSReza Sabdar * realink(2) doesn't null terminate the link name. We must 5792654012fSReza Sabdar * do it here. 5802654012fSReza Sabdar */ 5812654012fSReza Sabdar buf[len] = '\0'; 5822654012fSReza Sabdar } else { 5832654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Error %d reading softlink of [%s]", 5842654012fSReza Sabdar errno, nm); 5852654012fSReza Sabdar buf[0] = '\0'; 5862654012fSReza Sabdar 5872654012fSReza Sabdar /* Backup the link if the destination missing */ 5882654012fSReza Sabdar if (errno == ENOENT) 5892654012fSReza Sabdar return (0); 5902654012fSReza Sabdar 5912654012fSReza Sabdar } 5922654012fSReza Sabdar 5932654012fSReza Sabdar return (len); 5942654012fSReza Sabdar } 5952654012fSReza Sabdar 596b6b15642SReza Sabdar /* 597b6b15642SReza Sabdar * Read the system attribute file in a single buffer to write 598b6b15642SReza Sabdar * it as a single write. A partial write to system attribute would 599b6b15642SReza Sabdar * cause an EINVAL on write. 600b6b15642SReza Sabdar */ 601b6b15642SReza Sabdar static char * 602b6b15642SReza Sabdar get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size, 603b6b15642SReza Sabdar tlm_cmd_t *lc) 604b6b15642SReza Sabdar { 605b6b15642SReza Sabdar int len; 606b6b15642SReza Sabdar long write_size; 607b6b15642SReza Sabdar 608b6b15642SReza Sabdar if (rec_size > buf_size) 609b6b15642SReza Sabdar return (rec); 610b6b15642SReza Sabdar 611b6b15642SReza Sabdar len = rec_size; 612b6b15642SReza Sabdar (void) memcpy(rec, buf, len); 613b6b15642SReza Sabdar buf += len; 614b6b15642SReza Sabdar while (rec_size < buf_size) { 615b6b15642SReza Sabdar rec = get_write_buffer(buf_size - rec_size, 616b6b15642SReza Sabdar &write_size, FALSE, lc); 617b6b15642SReza Sabdar if (!rec) 618b6b15642SReza Sabdar return (0); 619b6b15642SReza Sabdar 620b6b15642SReza Sabdar len = min(buf_size - rec_size, write_size); 621b6b15642SReza Sabdar (void) memcpy(rec, buf, len); 622b6b15642SReza Sabdar rec_size += len; 623b6b15642SReza Sabdar buf += len; 624b6b15642SReza Sabdar } 625b6b15642SReza Sabdar return (rec); 626b6b15642SReza Sabdar } 627b6b15642SReza Sabdar 6282654012fSReza Sabdar 6292654012fSReza Sabdar /* 6302654012fSReza Sabdar * tlm_output_xattr 6312654012fSReza Sabdar * 6322654012fSReza Sabdar * Put this file into the output buffers. 6332654012fSReza Sabdar */ 6342654012fSReza Sabdar /*ARGSUSED*/ 6352654012fSReza Sabdar longlong_t 6362654012fSReza Sabdar tlm_output_xattr(char *dir, char *name, char *chkdir, 6372654012fSReza Sabdar tlm_acls_t *tlm_acls, tlm_commands_t *commands, 6382654012fSReza Sabdar tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats) 6392654012fSReza Sabdar { 6402654012fSReza Sabdar char *fullname; /* directory + name */ 6412654012fSReza Sabdar char *snapname; /* snapshot name */ 6422654012fSReza Sabdar int section; /* section of a huge file */ 6432654012fSReza Sabdar int fd; 6440fd80060SReza Sabdar int afd = 0; 6452654012fSReza Sabdar longlong_t seek_spot = 0; /* location in the file */ 6462654012fSReza Sabdar /* for Multi Volume record */ 6472654012fSReza Sabdar u_longlong_t pos; 6482654012fSReza Sabdar DIR *dp; 6492654012fSReza Sabdar struct dirent *dtp; 6502654012fSReza Sabdar char *attrname; 6512654012fSReza Sabdar char *fnamep; 6522654012fSReza Sabdar int rv = 0; 6532654012fSReza Sabdar 6545181c2afSReza Sabdar if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) { 6552654012fSReza Sabdar return (TLM_NO_SOURCE_FILE); 656295e611fSReza Sabdar } 6572654012fSReza Sabdar 6582654012fSReza Sabdar fullname = ndmp_malloc(TLM_MAX_PATH_NAME); 6592654012fSReza Sabdar if (fullname == NULL) { 6602654012fSReza Sabdar free(fullname); 6612654012fSReza Sabdar return (-TLM_NO_SCRATCH_SPACE); 6622654012fSReza Sabdar } 6632654012fSReza Sabdar 6642654012fSReza Sabdar if (!tlm_cat_path(fullname, dir, name)) { 6652654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Path too long."); 6662654012fSReza Sabdar free(fullname); 6672654012fSReza Sabdar return (-TLM_NO_SCRATCH_SPACE); 6682654012fSReza Sabdar } 6692654012fSReza Sabdar 670b6b15642SReza Sabdar if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 && 671b6b15642SReza Sabdar sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) { 6722654012fSReza Sabdar free(fullname); 6732654012fSReza Sabdar return (0); 6742654012fSReza Sabdar } 6752654012fSReza Sabdar 6762654012fSReza Sabdar attrname = ndmp_malloc(TLM_MAX_PATH_NAME); 6772654012fSReza Sabdar snapname = ndmp_malloc(TLM_MAX_PATH_NAME); 6782654012fSReza Sabdar if (attrname == NULL || snapname == NULL) { 6792654012fSReza Sabdar rv = -TLM_NO_SCRATCH_SPACE; 6802654012fSReza Sabdar goto err_out; 6812654012fSReza Sabdar } 6822654012fSReza Sabdar 6832654012fSReza Sabdar if (!tlm_cat_path(snapname, chkdir, name)) { 6842654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Path too long."); 6852654012fSReza Sabdar rv = -TLM_NO_SCRATCH_SPACE; 6862654012fSReza Sabdar goto err_out; 6872654012fSReza Sabdar } 6882654012fSReza Sabdar 6892654012fSReza Sabdar fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname; 6902654012fSReza Sabdar 6912654012fSReza Sabdar /* 6922654012fSReza Sabdar * Open the file for reading. 6932654012fSReza Sabdar */ 694b6b15642SReza Sabdar fd = attropen(fnamep, ".", O_RDONLY); 6952654012fSReza Sabdar if (fd == -1) { 696b6b15642SReza Sabdar NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s][%s]", 697b6b15642SReza Sabdar fullname, fnamep); 6982654012fSReza Sabdar rv = TLM_NO_SOURCE_FILE; 6992654012fSReza Sabdar goto err_out; 7002654012fSReza Sabdar } 7012654012fSReza Sabdar 7022654012fSReza Sabdar pos = tlm_get_data_offset(local_commands); 7032654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "pos: %10lld [%s]", pos, name); 7042654012fSReza Sabdar 7052654012fSReza Sabdar section = 0; 7062654012fSReza Sabdar 7072654012fSReza Sabdar dp = (DIR *)fdopendir(fd); 7082654012fSReza Sabdar if (dp == NULL) { 7092654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "BACKUP> Can't open file [%s]", fullname); 7102654012fSReza Sabdar (void) close(fd); 7112654012fSReza Sabdar rv = TLM_NO_SOURCE_FILE; 7122654012fSReza Sabdar goto err_out; 7132654012fSReza Sabdar } 7142654012fSReza Sabdar 7152654012fSReza Sabdar while ((dtp = readdir(dp)) != NULL) { 7162654012fSReza Sabdar int section_size; 7172654012fSReza Sabdar 7182654012fSReza Sabdar if (*dtp->d_name == '.') 7192654012fSReza Sabdar continue; 7202654012fSReza Sabdar 721b6b15642SReza Sabdar if (sysattr_rdonly(dtp->d_name)) 722b6b15642SReza Sabdar continue; 723b6b15642SReza Sabdar 7240fd80060SReza Sabdar afd = attropen(fnamep, dtp->d_name, O_RDONLY); 7250fd80060SReza Sabdar if (afd == -1) { 7262654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 727b6b15642SReza Sabdar "problem(%d) opening xattr file [%s][%s]", errno, 728b6b15642SReza Sabdar fullname, fnamep); 7292654012fSReza Sabdar goto tear_down; 7302654012fSReza Sabdar } 7312654012fSReza Sabdar 7320fd80060SReza Sabdar (void) output_xattr_header(fullname, dtp->d_name, afd, 7332654012fSReza Sabdar tlm_acls, section, local_commands); 7342654012fSReza Sabdar (void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s", 7352654012fSReza Sabdar dtp->d_name); 7362654012fSReza Sabdar (void) output_file_header(attrname, "", tlm_acls, 0, 7372654012fSReza Sabdar local_commands); 7382654012fSReza Sabdar 7392654012fSReza Sabdar section_size = (long)llmin(tlm_acls->acl_attr.st_size, 7402654012fSReza Sabdar (longlong_t)TLM_MAX_TAR_IMAGE); 7412654012fSReza Sabdar 7422654012fSReza Sabdar /* We only can read upto one section extended attribute */ 7432654012fSReza Sabdar while (section_size > 0) { 7442654012fSReza Sabdar char *buf; 7452654012fSReza Sabdar long actual_size; 7462654012fSReza Sabdar int read_size; 747b6b15642SReza Sabdar int sysattr_read = 0; 748b6b15642SReza Sabdar char *rec; 749b6b15642SReza Sabdar int size; 7502654012fSReza Sabdar 7512654012fSReza Sabdar /* 7522654012fSReza Sabdar * check for Abort commands 7532654012fSReza Sabdar */ 7542654012fSReza Sabdar if (commands->tcs_reader != TLM_BACKUP_RUN) { 7552654012fSReza Sabdar local_commands->tc_writer = TLM_ABORT; 7562654012fSReza Sabdar goto tear_down; 7572654012fSReza Sabdar } 7582654012fSReza Sabdar 7592654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer[ 7602654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer_in]. 7612654012fSReza Sabdar tb_file_size = section_size; 7622654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer[ 7632654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer_in]. 7642654012fSReza Sabdar tb_seek_spot = seek_spot; 7652654012fSReza Sabdar 7662654012fSReza Sabdar buf = get_write_buffer(section_size, 7672654012fSReza Sabdar &actual_size, FALSE, local_commands); 7682654012fSReza Sabdar if (!buf) 7692654012fSReza Sabdar goto tear_down; 7702654012fSReza Sabdar 771b6b15642SReza Sabdar if ((actual_size < section_size) && 772b6b15642SReza Sabdar sysattr_rw(dtp->d_name)) { 773b6b15642SReza Sabdar rec = buf; 774b6b15642SReza Sabdar buf = ndmp_malloc(section_size); 775b6b15642SReza Sabdar if (!buf) 776b6b15642SReza Sabdar goto tear_down; 777b6b15642SReza Sabdar size = actual_size; 778b6b15642SReza Sabdar actual_size = section_size; 779b6b15642SReza Sabdar sysattr_read = 1; 780b6b15642SReza Sabdar } 781b6b15642SReza Sabdar 7822654012fSReza Sabdar /* 7832654012fSReza Sabdar * check for Abort commands 7842654012fSReza Sabdar */ 7852654012fSReza Sabdar if (commands->tcs_reader != TLM_BACKUP_RUN) { 7862654012fSReza Sabdar local_commands->tc_writer = TLM_ABORT; 7872654012fSReza Sabdar goto tear_down; 7882654012fSReza Sabdar } 7892654012fSReza Sabdar 7902654012fSReza Sabdar read_size = min(section_size, actual_size); 7910fd80060SReza Sabdar if ((actual_size = read(afd, buf, read_size)) < 0) 792b6b15642SReza Sabdar break; 793b6b15642SReza Sabdar 794b6b15642SReza Sabdar if (sysattr_read) { 795b6b15642SReza Sabdar if (get_write_one_buf(buf, rec, read_size, 796b6b15642SReza Sabdar size, local_commands) == 0) { 797b6b15642SReza Sabdar free(buf); 798b6b15642SReza Sabdar goto tear_down; 799b6b15642SReza Sabdar } 800b6b15642SReza Sabdar free(buf); 801b6b15642SReza Sabdar } 802b6b15642SReza Sabdar 803b6b15642SReza Sabdar 8042654012fSReza Sabdar NS_ADD(rdisk, actual_size); 8052654012fSReza Sabdar NS_INC(rfile); 8062654012fSReza Sabdar 8072654012fSReza Sabdar if (actual_size == -1) { 8082654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 8092654012fSReza Sabdar "problem(%d) reading file [%s][%s]", 8102654012fSReza Sabdar errno, fullname, snapname); 8112654012fSReza Sabdar goto tear_down; 8122654012fSReza Sabdar } 8132654012fSReza Sabdar seek_spot += actual_size; 8142654012fSReza Sabdar section_size -= actual_size; 8152654012fSReza Sabdar } 8160fd80060SReza Sabdar (void) close(afd); 8170fd80060SReza Sabdar afd = -1; 8182654012fSReza Sabdar } 8192654012fSReza Sabdar 8202654012fSReza Sabdar tear_down: 8212654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer[ 8222654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0; 8232654012fSReza Sabdar 8240fd80060SReza Sabdar if (afd > 0) 8250fd80060SReza Sabdar (void) close(afd); 8260fd80060SReza Sabdar 8270fd80060SReza Sabdar /* closedir closes fd too */ 8282654012fSReza Sabdar (void) closedir(dp); 8292654012fSReza Sabdar 8302654012fSReza Sabdar err_out: 8312654012fSReza Sabdar free(fullname); 8322654012fSReza Sabdar free(attrname); 8332654012fSReza Sabdar free(snapname); 8342654012fSReza Sabdar return (rv); 8352654012fSReza Sabdar } 8362654012fSReza Sabdar 8372654012fSReza Sabdar 8382654012fSReza Sabdar /* 8392654012fSReza Sabdar * tlm_output_file 8402654012fSReza Sabdar * 8412654012fSReza Sabdar * Put this file into the output buffers. 8422654012fSReza Sabdar */ 8432654012fSReza Sabdar longlong_t 8442654012fSReza Sabdar tlm_output_file(char *dir, char *name, char *chkdir, 8452654012fSReza Sabdar tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands, 8462654012fSReza Sabdar tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q) 8472654012fSReza Sabdar { 8482654012fSReza Sabdar char *fullname; /* directory + name */ 8492654012fSReza Sabdar char *snapname; /* snapshot name */ 8502654012fSReza Sabdar char *linkname; /* where this file points */ 8512654012fSReza Sabdar int section = 0; /* section of a huge file */ 8522654012fSReza Sabdar int fd; 8532654012fSReza Sabdar longlong_t real_size; /* the origional file size */ 8542654012fSReza Sabdar longlong_t file_size; /* real size of this file */ 8552654012fSReza Sabdar longlong_t seek_spot = 0; /* location in the file */ 8562654012fSReza Sabdar /* for Multi Volume record */ 8572654012fSReza Sabdar u_longlong_t pos; 8582654012fSReza Sabdar char *fnamep; 8592654012fSReza Sabdar 8602654012fSReza Sabdar /* Indicate whether a file with the same inode has been backed up. */ 8612654012fSReza Sabdar int hardlink_done = 0; 8622654012fSReza Sabdar 8632654012fSReza Sabdar /* 8642654012fSReza Sabdar * If a file with the same inode has been backed up, hardlink_pos holds 8652654012fSReza Sabdar * the tape offset of the data record. 8662654012fSReza Sabdar */ 8672654012fSReza Sabdar u_longlong_t hardlink_pos = 0; 8682654012fSReza Sabdar 8692654012fSReza Sabdar if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) { 8702654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Path too long [%s][%s]", dir, name); 8712654012fSReza Sabdar return (-TLM_NO_SCRATCH_SPACE); 8722654012fSReza Sabdar } 8732654012fSReza Sabdar 8742654012fSReza Sabdar fullname = ndmp_malloc(TLM_MAX_PATH_NAME); 8752654012fSReza Sabdar linkname = ndmp_malloc(TLM_MAX_PATH_NAME); 8762654012fSReza Sabdar snapname = ndmp_malloc(TLM_MAX_PATH_NAME); 8772654012fSReza Sabdar if (fullname == NULL || linkname == NULL || snapname == NULL) { 8782654012fSReza Sabdar real_size = -TLM_NO_SCRATCH_SPACE; 8792654012fSReza Sabdar goto err_out; 8802654012fSReza Sabdar } 8812654012fSReza Sabdar if (!tlm_cat_path(fullname, dir, name) || 8822654012fSReza Sabdar !tlm_cat_path(snapname, chkdir, name)) { 8832654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "Path too long."); 8842654012fSReza Sabdar real_size = -TLM_NO_SCRATCH_SPACE; 8852654012fSReza Sabdar goto err_out; 8862654012fSReza Sabdar } 8872654012fSReza Sabdar 8882654012fSReza Sabdar pos = tlm_get_data_offset(local_commands); 8892654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, "pos: %10lld [%s]", pos, name); 8902654012fSReza Sabdar 8915181c2afSReza Sabdar if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) { 8922654012fSReza Sabdar if (S_ISLNK(tlm_acls->acl_attr.st_mode)) { 8932654012fSReza Sabdar file_size = tlm_readlink(fullname, snapname, linkname, 8942654012fSReza Sabdar TLM_MAX_PATH_NAME-1); 8952654012fSReza Sabdar if (file_size < 0) { 8962654012fSReza Sabdar real_size = -ENOENT; 8972654012fSReza Sabdar goto err_out; 8982654012fSReza Sabdar } 899295e611fSReza Sabdar } 9002654012fSReza Sabdar 9012654012fSReza Sabdar /* 9022654012fSReza Sabdar * Since soft links can not be read(2), we should only 9032654012fSReza Sabdar * backup the file header. 9042654012fSReza Sabdar */ 9052654012fSReza Sabdar (void) output_file_header(fullname, 9062654012fSReza Sabdar linkname, 9072654012fSReza Sabdar tlm_acls, 9082654012fSReza Sabdar section, 9092654012fSReza Sabdar local_commands); 9102654012fSReza Sabdar 9112654012fSReza Sabdar (void) tlm_log_fhnode(job_stats, dir, name, 9122654012fSReza Sabdar &tlm_acls->acl_attr, pos); 9132654012fSReza Sabdar (void) tlm_log_fhpath_name(job_stats, fullname, 9142654012fSReza Sabdar &tlm_acls->acl_attr, pos); 9152654012fSReza Sabdar 9162654012fSReza Sabdar free(fullname); 9172654012fSReza Sabdar free(linkname); 9182654012fSReza Sabdar free(snapname); 9192654012fSReza Sabdar return (0); 9202654012fSReza Sabdar } 9212654012fSReza Sabdar 9222654012fSReza Sabdar fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname; 9232654012fSReza Sabdar 9242654012fSReza Sabdar /* 9252654012fSReza Sabdar * For hardlink, only read the data if no other link 9262654012fSReza Sabdar * belonging to the same inode has been backed up. 9272654012fSReza Sabdar */ 9282654012fSReza Sabdar if (tlm_acls->acl_attr.st_nlink > 1) { 9292654012fSReza Sabdar hardlink_done = !hardlink_q_get(hardlink_q, 9302654012fSReza Sabdar tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL); 9312654012fSReza Sabdar } 9322654012fSReza Sabdar 9332654012fSReza Sabdar if (!hardlink_done) { 9342654012fSReza Sabdar /* 9352654012fSReza Sabdar * Open the file for reading. 9362654012fSReza Sabdar */ 9372654012fSReza Sabdar fd = open(fnamep, O_RDONLY); 9382654012fSReza Sabdar if (fd == -1) { 9392654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 940b6b15642SReza Sabdar "BACKUP> Can't open file [%s][%s] err(%d)", 941b6b15642SReza Sabdar fullname, fnamep, errno); 9422654012fSReza Sabdar real_size = -TLM_NO_SOURCE_FILE; 9432654012fSReza Sabdar goto err_out; 9442654012fSReza Sabdar } 9452654012fSReza Sabdar } else { 9467bc22e45SReza Sabdar NDMP_LOG(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ", 9472654012fSReza Sabdar tlm_acls->acl_attr.st_ino, hardlink_pos); 9482654012fSReza Sabdar 9492654012fSReza Sabdar fd = -1; 9502654012fSReza Sabdar } 9512654012fSReza Sabdar 9522654012fSReza Sabdar linkname[0] = 0; 9532654012fSReza Sabdar 9542654012fSReza Sabdar real_size = tlm_acls->acl_attr.st_size; 9552654012fSReza Sabdar (void) output_acl_header(&tlm_acls->acl_info, 9562654012fSReza Sabdar local_commands); 9572654012fSReza Sabdar 9582654012fSReza Sabdar /* 9592654012fSReza Sabdar * section = 0: file is small enough for TAR 9602654012fSReza Sabdar * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks 9612654012fSReza Sabdar * and the file name gets munged 9622654012fSReza Sabdar */ 9632654012fSReza Sabdar file_size = real_size; 9642654012fSReza Sabdar if (file_size > TLM_MAX_TAR_IMAGE) { 9652654012fSReza Sabdar if (output_humongus_header(fullname, file_size, 9662654012fSReza Sabdar local_commands) < 0) { 9672654012fSReza Sabdar (void) close(fd); 9682654012fSReza Sabdar real_size = -TLM_NO_SCRATCH_SPACE; 9692654012fSReza Sabdar goto err_out; 9702654012fSReza Sabdar } 9712654012fSReza Sabdar section = 1; 9722654012fSReza Sabdar } else { 9732654012fSReza Sabdar section = 0; 9742654012fSReza Sabdar } 9752654012fSReza Sabdar 9762654012fSReza Sabdar /* 9772654012fSReza Sabdar * For hardlink, if other link belonging to the same inode 9782654012fSReza Sabdar * has been backed up, only backup an empty record. 9792654012fSReza Sabdar */ 9802654012fSReza Sabdar if (hardlink_done) 9812654012fSReza Sabdar file_size = 0; 9822654012fSReza Sabdar 9832654012fSReza Sabdar /* 9842654012fSReza Sabdar * work 9852654012fSReza Sabdar */ 9862654012fSReza Sabdar if (file_size == 0) { 9872654012fSReza Sabdar (void) output_file_header(fullname, 9882654012fSReza Sabdar linkname, 9892654012fSReza Sabdar tlm_acls, 9902654012fSReza Sabdar section, 9912654012fSReza Sabdar local_commands); 9922654012fSReza Sabdar /* 9932654012fSReza Sabdar * this can fall right through since zero size files 9942654012fSReza Sabdar * will be skipped by the WHILE loop anyway 9952654012fSReza Sabdar */ 9962654012fSReza Sabdar } 9972654012fSReza Sabdar 9982654012fSReza Sabdar while (file_size > 0) { 9992654012fSReza Sabdar int section_size = llmin(file_size, 10002654012fSReza Sabdar (longlong_t)TLM_MAX_TAR_IMAGE); 10012654012fSReza Sabdar 10022654012fSReza Sabdar tlm_acls->acl_attr.st_size = (longlong_t)section_size; 10032654012fSReza Sabdar (void) output_file_header(fullname, 10042654012fSReza Sabdar linkname, 10052654012fSReza Sabdar tlm_acls, 10062654012fSReza Sabdar section, 10072654012fSReza Sabdar local_commands); 10082654012fSReza Sabdar while (section_size > 0) { 10092654012fSReza Sabdar char *buf; 10102654012fSReza Sabdar long actual_size; 10112654012fSReza Sabdar int read_size; 10122654012fSReza Sabdar 10132654012fSReza Sabdar /* 10142654012fSReza Sabdar * check for Abort commands 10152654012fSReza Sabdar */ 10162654012fSReza Sabdar if (commands->tcs_reader != TLM_BACKUP_RUN) { 10172654012fSReza Sabdar local_commands->tc_writer = TLM_ABORT; 10182654012fSReza Sabdar goto tear_down; 10192654012fSReza Sabdar } 10202654012fSReza Sabdar 10212654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer[ 10222654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer_in]. 10232654012fSReza Sabdar tb_file_size = section_size; 10242654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer[ 10252654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer_in]. 10262654012fSReza Sabdar tb_seek_spot = seek_spot; 10272654012fSReza Sabdar 10282654012fSReza Sabdar buf = get_write_buffer(section_size, 10292654012fSReza Sabdar &actual_size, FALSE, local_commands); 10302654012fSReza Sabdar if (!buf) 10312654012fSReza Sabdar goto tear_down; 10322654012fSReza Sabdar 10332654012fSReza Sabdar /* 10342654012fSReza Sabdar * check for Abort commands 10352654012fSReza Sabdar */ 10362654012fSReza Sabdar if (commands->tcs_reader != TLM_BACKUP_RUN) { 10372654012fSReza Sabdar local_commands->tc_writer = TLM_ABORT; 10382654012fSReza Sabdar goto tear_down; 10392654012fSReza Sabdar } 10402654012fSReza Sabdar 10412654012fSReza Sabdar read_size = min(section_size, actual_size); 10422654012fSReza Sabdar actual_size = read(fd, buf, read_size); 10432654012fSReza Sabdar NS_ADD(rdisk, actual_size); 10442654012fSReza Sabdar NS_INC(rfile); 10452654012fSReza Sabdar 10462654012fSReza Sabdar if (actual_size == 0) 10472654012fSReza Sabdar break; 10482654012fSReza Sabdar 10492654012fSReza Sabdar if (actual_size == -1) { 10502654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 10512654012fSReza Sabdar "problem(%d) reading file [%s][%s]", 10522654012fSReza Sabdar errno, fullname, snapname); 10532654012fSReza Sabdar goto tear_down; 10542654012fSReza Sabdar } 10552654012fSReza Sabdar seek_spot += actual_size; 10562654012fSReza Sabdar file_size -= actual_size; 10572654012fSReza Sabdar section_size -= actual_size; 10582654012fSReza Sabdar } 10592654012fSReza Sabdar section++; 10602654012fSReza Sabdar } 10612654012fSReza Sabdar 10622654012fSReza Sabdar /* 10632654012fSReza Sabdar * If data belonging to this hardlink has been backed up, add the link 10642654012fSReza Sabdar * to hardlink queue. 10652654012fSReza Sabdar */ 10662654012fSReza Sabdar if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) { 10672654012fSReza Sabdar (void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino, 10682654012fSReza Sabdar pos, NULL, 0); 10692654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 10707bc22e45SReza Sabdar "backed up hardlink file %s, inode = %llu, pos = %llu ", 10712654012fSReza Sabdar fullname, tlm_acls->acl_attr.st_ino, pos); 10722654012fSReza Sabdar } 10732654012fSReza Sabdar 10742654012fSReza Sabdar /* 10752654012fSReza Sabdar * For hardlink, if other link belonging to the same inode has been 10767bc22e45SReza Sabdar * backed up, no add_node entry should be sent for this link. 10772654012fSReza Sabdar */ 10782654012fSReza Sabdar if (hardlink_done) { 10792654012fSReza Sabdar NDMP_LOG(LOG_DEBUG, 10807bc22e45SReza Sabdar "backed up hardlink link %s, inode = %llu, pos = %llu ", 10812654012fSReza Sabdar fullname, tlm_acls->acl_attr.st_ino, hardlink_pos); 10822654012fSReza Sabdar } else { 10832654012fSReza Sabdar (void) tlm_log_fhnode(job_stats, dir, name, 10842654012fSReza Sabdar &tlm_acls->acl_attr, pos); 10852654012fSReza Sabdar } 10862654012fSReza Sabdar 10872654012fSReza Sabdar (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr, 10882654012fSReza Sabdar pos); 10892654012fSReza Sabdar 10902654012fSReza Sabdar tear_down: 10912654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer[ 10922654012fSReza Sabdar local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0; 10932654012fSReza Sabdar 10942654012fSReza Sabdar (void) close(fd); 10952654012fSReza Sabdar 10962654012fSReza Sabdar err_out: 10972654012fSReza Sabdar free(fullname); 10982654012fSReza Sabdar free(linkname); 10992654012fSReza Sabdar free(snapname); 11002654012fSReza Sabdar return (real_size); 11012654012fSReza Sabdar } 11022654012fSReza Sabdar 11032654012fSReza Sabdar /* 11042654012fSReza Sabdar * tar_putfile 11052654012fSReza Sabdar * 11062654012fSReza Sabdar * Main file backup function for tar 11072654012fSReza Sabdar */ 11082654012fSReza Sabdar int 11092654012fSReza Sabdar tar_putfile(char *dir, char *name, char *chkdir, 11102654012fSReza Sabdar tlm_acls_t *tlm_acls, tlm_commands_t *commands, 11112654012fSReza Sabdar tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats, 11122654012fSReza Sabdar struct hardlink_q *hardlink_q) 11132654012fSReza Sabdar { 11142654012fSReza Sabdar int rv; 11152654012fSReza Sabdar 11162654012fSReza Sabdar rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands, 11172654012fSReza Sabdar local_commands, job_stats, hardlink_q); 11182654012fSReza Sabdar if (rv < 0) 11192654012fSReza Sabdar return (rv); 11202654012fSReza Sabdar 11212654012fSReza Sabdar rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands, 11222654012fSReza Sabdar local_commands, job_stats); 11232654012fSReza Sabdar 11242654012fSReza Sabdar return (rv < 0 ? rv : 0); 11252654012fSReza Sabdar } 11262654012fSReza Sabdar 11272654012fSReza Sabdar /* 11282654012fSReza Sabdar * get_write_buffer 11292654012fSReza Sabdar * 11302654012fSReza Sabdar * a wrapper to tlm_get_write_buffer so that 11312654012fSReza Sabdar * we can cleanly detect ABORT commands 11322654012fSReza Sabdar * without involving the TLM library with 11332654012fSReza Sabdar * our problems. 11342654012fSReza Sabdar */ 11352654012fSReza Sabdar static char * 11362654012fSReza Sabdar get_write_buffer(long size, long *actual_size, 11372654012fSReza Sabdar boolean_t zero, tlm_cmd_t *local_commands) 11382654012fSReza Sabdar { 11392654012fSReza Sabdar while (local_commands->tc_reader == TLM_BACKUP_RUN) { 11402654012fSReza Sabdar char *rec = tlm_get_write_buffer(size, actual_size, 11412654012fSReza Sabdar local_commands->tc_buffers, zero); 11422654012fSReza Sabdar if (rec != 0) { 11432654012fSReza Sabdar return (rec); 11442654012fSReza Sabdar } 11452654012fSReza Sabdar } 11462654012fSReza Sabdar return (NULL); 11472654012fSReza Sabdar } 11482654012fSReza Sabdar 11492654012fSReza Sabdar #define NDMP_MORE_RECORDS 2 11502654012fSReza Sabdar 11512654012fSReza Sabdar /* 11522654012fSReza Sabdar * write_tar_eof 11532654012fSReza Sabdar * 11542654012fSReza Sabdar * This function is initially written for NDMP support. It appends 11552654012fSReza Sabdar * two tar headers to the tar file, and also N more empty buffers 11562654012fSReza Sabdar * to make sure that the two tar headers will be read as a part of 11572654012fSReza Sabdar * a mover record and don't get locked because of EOM on the mover 11582654012fSReza Sabdar * side. 11592654012fSReza Sabdar */ 11602654012fSReza Sabdar void 11612654012fSReza Sabdar write_tar_eof(tlm_cmd_t *local_commands) 11622654012fSReza Sabdar { 11632654012fSReza Sabdar int i; 11642654012fSReza Sabdar long actual_size; 11652654012fSReza Sabdar tlm_buffers_t *bufs; 11662654012fSReza Sabdar 11672654012fSReza Sabdar /* 11682654012fSReza Sabdar * output 2 zero filled records, 11692654012fSReza Sabdar * TAR wants this. 11702654012fSReza Sabdar */ 11712654012fSReza Sabdar (void) get_write_buffer(sizeof (tlm_tar_hdr_t), 11722654012fSReza Sabdar &actual_size, TRUE, local_commands); 11732654012fSReza Sabdar (void) get_write_buffer(sizeof (tlm_tar_hdr_t), 11742654012fSReza Sabdar &actual_size, TRUE, local_commands); 11752654012fSReza Sabdar 11762654012fSReza Sabdar /* 11772654012fSReza Sabdar * NDMP: Clear the rest of the buffer and write two more buffers 11782654012fSReza Sabdar * to the tape. 11792654012fSReza Sabdar */ 11802654012fSReza Sabdar bufs = local_commands->tc_buffers; 11812654012fSReza Sabdar (void) get_write_buffer(bufs->tbs_data_transfer_size, 11822654012fSReza Sabdar &actual_size, TRUE, local_commands); 11832654012fSReza Sabdar 11842654012fSReza Sabdar for (i = 0; i < NDMP_MORE_RECORDS && 11852654012fSReza Sabdar local_commands->tc_reader == TLM_BACKUP_RUN; i++) { 11862654012fSReza Sabdar /* 11872654012fSReza Sabdar * We don't need the return value of get_write_buffer(), 11882654012fSReza Sabdar * since it's already zeroed out if the buffer is returned. 11892654012fSReza Sabdar */ 11902654012fSReza Sabdar (void) get_write_buffer(bufs->tbs_data_transfer_size, 11912654012fSReza Sabdar &actual_size, TRUE, local_commands); 11922654012fSReza Sabdar } 11932654012fSReza Sabdar 11942654012fSReza Sabdar bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE; 11952654012fSReza Sabdar tlm_buffer_release_in_buf(bufs); 11962654012fSReza Sabdar } 11972654012fSReza Sabdar 11982654012fSReza Sabdar /* 11992654012fSReza Sabdar * Callback to backup each ZFS property 12002654012fSReza Sabdar */ 12012654012fSReza Sabdar static int 12022654012fSReza Sabdar zfs_put_prop_cb(int prop, void *pp) 12032654012fSReza Sabdar { 120442ed7838SReza Sabdar ndmp_metadata_handle_t *mhd; 120542ed7838SReza Sabdar ndmp_metadata_header_ext_t *mhp; 120642ed7838SReza Sabdar ndmp_metadata_property_ext_t *mpp; 120742ed7838SReza Sabdar char vbuf[ZFS_MAXPROPLEN]; 120842ed7838SReza Sabdar char sbuf[ZFS_MAXPROPLEN]; 12092654012fSReza Sabdar zprop_source_t stype; 121086c48bbfSReza Sabdar char *sourcestr; 12112654012fSReza Sabdar 12122654012fSReza Sabdar if (pp == NULL) 12132654012fSReza Sabdar return (ZPROP_INVAL); 12142654012fSReza Sabdar 121542ed7838SReza Sabdar mhd = (ndmp_metadata_handle_t *)pp; 121642ed7838SReza Sabdar mhp = mhd->ml_xhdr; 121742ed7838SReza Sabdar mpp = &mhp->nh_property[mhp->nh_count]; 12182654012fSReza Sabdar 121942ed7838SReza Sabdar if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) + 122042ed7838SReza Sabdar sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes) 122142ed7838SReza Sabdar return (ZPROP_INVAL); 122242ed7838SReza Sabdar 122342ed7838SReza Sabdar if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf), 122442ed7838SReza Sabdar &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) { 122542ed7838SReza Sabdar mhp->nh_count++; 1226674cb4b0SReza Sabdar return (ZPROP_CONT); 122742ed7838SReza Sabdar } 1228674cb4b0SReza Sabdar 1229*40a5c998SMatthew Ahrens (void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop), 1230*40a5c998SMatthew Ahrens ZFS_MAX_DATASET_NAME_LEN); 123142ed7838SReza Sabdar (void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN); 123286c48bbfSReza Sabdar 123386c48bbfSReza Sabdar switch (stype) { 123486c48bbfSReza Sabdar case ZPROP_SRC_NONE: 123586c48bbfSReza Sabdar sourcestr = "none"; 123686c48bbfSReza Sabdar break; 123742ed7838SReza Sabdar case ZPROP_SRC_RECEIVED: 123842ed7838SReza Sabdar sourcestr = "received"; 123942ed7838SReza Sabdar break; 124086c48bbfSReza Sabdar case ZPROP_SRC_LOCAL: 124186c48bbfSReza Sabdar sourcestr = mhp->nh_dataset; 124286c48bbfSReza Sabdar break; 124386c48bbfSReza Sabdar case ZPROP_SRC_TEMPORARY: 124486c48bbfSReza Sabdar sourcestr = "temporary"; 124586c48bbfSReza Sabdar break; 124686c48bbfSReza Sabdar case ZPROP_SRC_DEFAULT: 124786c48bbfSReza Sabdar sourcestr = "default"; 124886c48bbfSReza Sabdar break; 124986c48bbfSReza Sabdar default: 125086c48bbfSReza Sabdar sourcestr = sbuf; 125186c48bbfSReza Sabdar break; 125286c48bbfSReza Sabdar } 125342ed7838SReza Sabdar (void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN); 12542654012fSReza Sabdar 125542ed7838SReza Sabdar mhp->nh_count++; 12562654012fSReza Sabdar return (ZPROP_CONT); 12572654012fSReza Sabdar } 12582654012fSReza Sabdar 125942ed7838SReza Sabdar /* 126042ed7838SReza Sabdar * Callback to backup each ZFS user/group quota 126142ed7838SReza Sabdar */ 126242ed7838SReza Sabdar static int 126342ed7838SReza Sabdar zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space) 126442ed7838SReza Sabdar { 126542ed7838SReza Sabdar ndmp_metadata_handle_t *mhd; 126642ed7838SReza Sabdar ndmp_metadata_header_ext_t *mhp; 126742ed7838SReza Sabdar ndmp_metadata_property_ext_t *mpp; 126842ed7838SReza Sabdar char *typestr; 126942ed7838SReza Sabdar 127042ed7838SReza Sabdar if (pp == NULL) 127142ed7838SReza Sabdar return (ZPROP_INVAL); 127242ed7838SReza Sabdar 127342ed7838SReza Sabdar mhd = (ndmp_metadata_handle_t *)pp; 127442ed7838SReza Sabdar mhp = mhd->ml_xhdr; 127542ed7838SReza Sabdar mpp = &mhp->nh_property[mhp->nh_count]; 127642ed7838SReza Sabdar 127742ed7838SReza Sabdar if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) + 127842ed7838SReza Sabdar sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes) 127942ed7838SReza Sabdar return (ZPROP_INVAL); 128042ed7838SReza Sabdar 128142ed7838SReza Sabdar if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA) 128242ed7838SReza Sabdar typestr = "userquota"; 128342ed7838SReza Sabdar else 128442ed7838SReza Sabdar typestr = "groupquota"; 128542ed7838SReza Sabdar 1286*40a5c998SMatthew Ahrens if (domain == NULL || *domain == '\0') { 1287*40a5c998SMatthew Ahrens (void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN, 1288*40a5c998SMatthew Ahrens "%s@%llu", typestr, (longlong_t)rid); 1289*40a5c998SMatthew Ahrens } else { 1290*40a5c998SMatthew Ahrens (void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN, 1291*40a5c998SMatthew Ahrens "%s@%s-%llu", typestr, domain, (longlong_t)rid); 1292*40a5c998SMatthew Ahrens } 129342ed7838SReza Sabdar (void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space); 129442ed7838SReza Sabdar (void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN); 129542ed7838SReza Sabdar 129642ed7838SReza Sabdar mhp->nh_count++; 129742ed7838SReza Sabdar return (0); 129842ed7838SReza Sabdar } 129942ed7838SReza Sabdar 130042ed7838SReza Sabdar /* 130142ed7838SReza Sabdar * Callback to count each ZFS property 130242ed7838SReza Sabdar */ 130342ed7838SReza Sabdar /*ARGSUSED*/ 130442ed7838SReza Sabdar static int 130542ed7838SReza Sabdar zfs_count_prop_cb(int prop, void *pp) 130642ed7838SReza Sabdar { 130742ed7838SReza Sabdar (*(int *)pp)++; 130842ed7838SReza Sabdar return (ZPROP_CONT); 130942ed7838SReza Sabdar } 131042ed7838SReza Sabdar 131142ed7838SReza Sabdar /* 131242ed7838SReza Sabdar * Callback to count each ZFS user/group quota 131342ed7838SReza Sabdar */ 131442ed7838SReza Sabdar /*ARGSUSED*/ 131542ed7838SReza Sabdar static int 131642ed7838SReza Sabdar zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space) 131742ed7838SReza Sabdar { 131842ed7838SReza Sabdar (*(int *)pp)++; 131942ed7838SReza Sabdar return (0); 132042ed7838SReza Sabdar } 132142ed7838SReza Sabdar 132242ed7838SReza Sabdar /* 132342ed7838SReza Sabdar * Count the number of ZFS properties and user/group quotas 132442ed7838SReza Sabdar */ 132542ed7838SReza Sabdar int 132642ed7838SReza Sabdar zfs_get_prop_counts(zfs_handle_t *zhp) 132742ed7838SReza Sabdar { 132842ed7838SReza Sabdar int count = 0; 132942ed7838SReza Sabdar nvlist_t *uprops; 133042ed7838SReza Sabdar nvpair_t *elp; 133142ed7838SReza Sabdar 133242ed7838SReza Sabdar if (zhp == NULL) 133342ed7838SReza Sabdar return (0); 133442ed7838SReza Sabdar 133542ed7838SReza Sabdar (void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE, 133642ed7838SReza Sabdar ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET); 133742ed7838SReza Sabdar 133842ed7838SReza Sabdar (void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb, 133942ed7838SReza Sabdar &count); 134042ed7838SReza Sabdar (void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb, 134142ed7838SReza Sabdar &count); 134242ed7838SReza Sabdar 134342ed7838SReza Sabdar uprops = zfs_get_user_props(zhp); 134442ed7838SReza Sabdar 134542ed7838SReza Sabdar elp = nvlist_next_nvpair(uprops, NULL); 134642ed7838SReza Sabdar for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp)) 134742ed7838SReza Sabdar count++; 134842ed7838SReza Sabdar 134942ed7838SReza Sabdar return (count); 135042ed7838SReza Sabdar } 13512654012fSReza Sabdar 13522654012fSReza Sabdar /* 13532654012fSReza Sabdar * Notifies ndmpd that the metadata associated with the given ZFS dataset 13542654012fSReza Sabdar * should be backed up. 13552654012fSReza Sabdar */ 13562654012fSReza Sabdar int 13572654012fSReza Sabdar ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset) 13582654012fSReza Sabdar { 13592654012fSReza Sabdar tlm_commands_t *cmds; 136042ed7838SReza Sabdar ndmp_metadata_handle_t mhd; 136142ed7838SReza Sabdar ndmp_metadata_header_ext_t *mhp; 136242ed7838SReza Sabdar ndmp_metadata_property_ext_t *mpp; 136342ed7838SReza Sabdar zfs_handle_t *zhp; 13642654012fSReza Sabdar tlm_cmd_t *lcmd; 13652654012fSReza Sabdar long actual_size; 13662654012fSReza Sabdar nvlist_t *uprops, *ulist; 13672654012fSReza Sabdar const char *pname; 13682654012fSReza Sabdar nvpair_t *elp; 13692654012fSReza Sabdar char *sval, *ssrc; 13702654012fSReza Sabdar char *wbuf, *pp, *tp; 13712654012fSReza Sabdar long size, lsize, sz; 13722654012fSReza Sabdar int align = RECORDSIZE - 1; 137342ed7838SReza Sabdar int pcount; 13742654012fSReza Sabdar 13752654012fSReza Sabdar if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL) 13762654012fSReza Sabdar return (-1); 13772654012fSReza Sabdar 13782654012fSReza Sabdar if ((lcmd = cmds->tcs_command) == NULL || 13792654012fSReza Sabdar lcmd->tc_buffers == NULL) 13802654012fSReza Sabdar return (-1); 13812654012fSReza Sabdar 138242ed7838SReza Sabdar (void) mutex_lock(&zlib_mtx); 138342ed7838SReza Sabdar if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) { 138442ed7838SReza Sabdar (void) mutex_unlock(&zlib_mtx); 138542ed7838SReza Sabdar return (-1); 138642ed7838SReza Sabdar } 138742ed7838SReza Sabdar 138842ed7838SReza Sabdar pcount = zfs_get_prop_counts(zhp); 138942ed7838SReza Sabdar size = sizeof (ndmp_metadata_header_ext_t) + 139042ed7838SReza Sabdar pcount * sizeof (ndmp_metadata_property_ext_t); 139142ed7838SReza Sabdar 13922654012fSReza Sabdar size += align; 13932654012fSReza Sabdar size &= ~align; 13942654012fSReza Sabdar 139542ed7838SReza Sabdar if ((mhp = malloc(size)) == NULL) { 139642ed7838SReza Sabdar zfs_close(zhp); 139789f9eb87SReza Sabdar (void) mutex_unlock(&zlib_mtx); 139842ed7838SReza Sabdar return (-1); 13992654012fSReza Sabdar } 14002654012fSReza Sabdar 140142ed7838SReza Sabdar (void) memset(mhp, 0, size); 140242ed7838SReza Sabdar 140342ed7838SReza Sabdar mhd.ml_handle = zhp; 140442ed7838SReza Sabdar mhd.ml_xhdr = mhp; 140542ed7838SReza Sabdar mhp->nh_total_bytes = size; 140642ed7838SReza Sabdar mhp->nh_major = META_HDR_MAJOR_VERSION; 140742ed7838SReza Sabdar mhp->nh_minor = META_HDR_MINOR_VERSION; 140842ed7838SReza Sabdar mhp->nh_plversion = nctx->nc_plversion; 140942ed7838SReza Sabdar 141042ed7838SReza Sabdar (void) strlcpy(mhp->nh_plname, nctx->nc_plname, 141142ed7838SReza Sabdar sizeof (mhp->nh_plname)); 141242ed7838SReza Sabdar (void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT, 141342ed7838SReza Sabdar sizeof (mhp->nh_magic)); 141442ed7838SReza Sabdar (void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset)); 141542ed7838SReza Sabdar 14162654012fSReza Sabdar /* Get all the ZFS properties */ 141742ed7838SReza Sabdar (void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE, 14182654012fSReza Sabdar ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET); 14192654012fSReza Sabdar 14202654012fSReza Sabdar /* Get user properties */ 142142ed7838SReza Sabdar uprops = zfs_get_user_props(mhd.ml_handle); 14222654012fSReza Sabdar 14232654012fSReza Sabdar elp = nvlist_next_nvpair(uprops, NULL); 14242654012fSReza Sabdar 14252654012fSReza Sabdar while (elp != NULL) { 14262654012fSReza Sabdar mpp = &mhp->nh_property[mhp->nh_count]; 14272654012fSReza Sabdar if (nvpair_value_nvlist(elp, &ulist) != 0 || 14282654012fSReza Sabdar nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 || 14292654012fSReza Sabdar nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) { 143042ed7838SReza Sabdar zfs_close(mhd.ml_handle); 143189f9eb87SReza Sabdar (void) mutex_unlock(&zlib_mtx); 14322654012fSReza Sabdar free(mhp); 14332654012fSReza Sabdar return (-1); 14342654012fSReza Sabdar } 1435*40a5c998SMatthew Ahrens if ((pname = nvpair_name(elp)) != NULL) { 1436*40a5c998SMatthew Ahrens (void) strlcpy(mpp->mp_name, pname, 1437*40a5c998SMatthew Ahrens ZFS_MAX_DATASET_NAME_LEN); 1438*40a5c998SMatthew Ahrens } 14392654012fSReza Sabdar 144042ed7838SReza Sabdar (void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN); 144142ed7838SReza Sabdar (void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN); 14422654012fSReza Sabdar mhp->nh_count++; 14432654012fSReza Sabdar elp = nvlist_next_nvpair(uprops, elp); 14442654012fSReza Sabdar } 14452654012fSReza Sabdar 144642ed7838SReza Sabdar mhd.ml_quota_prop = ZFS_PROP_USERQUOTA; 144742ed7838SReza Sabdar (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA, 144842ed7838SReza Sabdar zfs_put_quota_cb, &mhd); 144942ed7838SReza Sabdar mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA; 145042ed7838SReza Sabdar (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA, 145142ed7838SReza Sabdar zfs_put_quota_cb, &mhd); 145242ed7838SReza Sabdar mhp->nh_count = pcount; 145342ed7838SReza Sabdar 145442ed7838SReza Sabdar zfs_close(mhd.ml_handle); 145589f9eb87SReza Sabdar (void) mutex_unlock(&zlib_mtx); 14562654012fSReza Sabdar 14572654012fSReza Sabdar if ((wbuf = get_write_buffer(size, &actual_size, TRUE, 14582654012fSReza Sabdar lcmd)) != NULL) { 14592654012fSReza Sabdar pp = (char *)mhp; 14602654012fSReza Sabdar 14612654012fSReza Sabdar (void) memcpy(wbuf, pp, (actual_size < size) ? 14622654012fSReza Sabdar actual_size : size); 14632654012fSReza Sabdar pp += (actual_size < size) ? actual_size : size; 14642654012fSReza Sabdar 14652654012fSReza Sabdar sz = actual_size; 14662654012fSReza Sabdar while (sz < size && 14672654012fSReza Sabdar ((tp = get_write_buffer(size - sz, &lsize, 14682654012fSReza Sabdar TRUE, lcmd))) != NULL) { 146942ed7838SReza Sabdar (void) memcpy(tp, pp, lsize); 14702654012fSReza Sabdar sz += lsize; 14712654012fSReza Sabdar pp += lsize; 14722654012fSReza Sabdar } 14732654012fSReza Sabdar if (sz > size) { 14742654012fSReza Sabdar tlm_unget_write_buffer(lcmd->tc_buffers, sz - size); 14752654012fSReza Sabdar } 14762654012fSReza Sabdar } 14772654012fSReza Sabdar 14782654012fSReza Sabdar free(mhp); 14792654012fSReza Sabdar return (0); 14802654012fSReza Sabdar } 1481