1 /*
   2  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2015 by Delphix. All rights reserved.
   4  */
   5 
   6 /*
   7  * BSD 3 Clause License
   8  *
   9  * Copyright (c) 2007, The Storage Networking Industry Association.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  *      - Redistributions of source code must retain the above copyright
  15  *        notice, this list of conditions and the following disclaimer.
  16  *
  17  *      - Redistributions in binary form must reproduce the above copyright
  18  *        notice, this list of conditions and the following disclaimer in
  19  *        the documentation and/or other materials provided with the
  20  *        distribution.
  21  *
  22  *      - Neither the name of The Storage Networking Industry Association (SNIA)
  23  *        nor the names of its contributors may be used to endorse or promote
  24  *        products derived from this software without specific prior written
  25  *        permission.
  26  *
  27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  28  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  31  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37  * POSSIBILITY OF SUCH DAMAGE.
  38  */
  39 /* Copyright 2017 Nexenta Systems, Inc. All rights reserved. */
  40 
  41 #include <syslog.h>
  42 #include <stdio.h>
  43 #include <limits.h>
  44 #include <time.h>
  45 #include <sys/stat.h>
  46 #include <unistd.h>
  47 #include <dirent.h>
  48 #include <pthread.h>
  49 #include <archives.h>
  50 #include <tlm.h>
  51 #include <sys/fs/zfs.h>
  52 #include <sys/mkdev.h>
  53 #include <libzfs.h>
  54 #include <libcmdutils.h>
  55 #include <pwd.h>
  56 #include <grp.h>
  57 #include "tlm_proto.h"
  58 
  59 
  60 static char *get_write_buffer(long size,
  61     long *actual_size,
  62     boolean_t zero,
  63     tlm_cmd_t *);
  64 static int output_acl_header(sec_attr_t *,
  65     tlm_cmd_t *);
  66 static int output_file_header(char *name,
  67     char *link,
  68     tlm_acls_t *,
  69     int section,
  70     tlm_cmd_t *);
  71 static int output_xattr_header(char *fname,
  72     char *aname,
  73     int fd,
  74     tlm_acls_t *,
  75     int section,
  76     tlm_cmd_t *);
  77 
  78 extern  libzfs_handle_t *zlibh;
  79 extern  mutex_t zlib_mtx;
  80 
  81 #define S_ISPECIAL(a)   (S_ISLNK(a) || S_ISFIFO(a) || S_ISBLK(a) || \
  82         S_ISCHR(a))
  83 
  84 /*
  85  * output_mem
  86  *
  87  * Gets a IO write buffer and copies memory to the that.
  88  */
  89 static void
  90 output_mem(tlm_cmd_t *local_commands, char *mem,
  91     int len)
  92 {
  93         long actual_size, rec_size;
  94         char *rec;
  95 
  96         while (len > 0) {
  97                 rec = get_write_buffer(len, &actual_size,
  98                     FALSE, local_commands);
  99                 rec_size = min(actual_size, len);
 100                 (void) memcpy(rec, mem, rec_size);
 101                 mem += rec_size;
 102                 len -= rec_size;
 103         }
 104 }
 105 
 106 /*
 107  * tlm_output_dir
 108  *
 109  * Put the directory information into the output buffers.
 110  */
 111 int
 112 tlm_output_dir(char *name, tlm_acls_t *tlm_acls,
 113     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
 114 {
 115         u_longlong_t pos;
 116 
 117         /*
 118          * Send the node or path history of the directory itself.
 119          */
 120         pos = tlm_get_data_offset(local_commands);
 121         (void) tlm_log_fhnode(job_stats, name, "", &tlm_acls->acl_attr, pos);
 122         (void) tlm_log_fhpath_name(job_stats, name, &tlm_acls->acl_attr, pos);
 123         /* fhdir_cb is handled in ndmpd_tar3.c */
 124 
 125         (void) output_acl_header(&tlm_acls->acl_info,
 126             local_commands);
 127         (void) output_file_header(name, "", tlm_acls, 0,
 128             local_commands);
 129 
 130         return (0);
 131 }
 132 
 133 /*
 134  * tar_putdir
 135  *
 136  * Main dir backup function for tar
 137  */
 138 int
 139 tar_putdir(char *name, tlm_acls_t *tlm_acls,
 140     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
 141 {
 142         int rv;
 143 
 144         rv = tlm_output_dir(name, tlm_acls, local_commands, job_stats);
 145         return (rv < 0 ? rv : 0);
 146 }
 147 
 148 /*
 149  * output_acl_header
 150  *
 151  * output the ACL header record and data
 152  */
 153 static int
 154 output_acl_header(sec_attr_t *acl_info,
 155     tlm_cmd_t *local_commands)
 156 {
 157         long    actual_size;
 158         tlm_tar_hdr_t *tar_hdr;
 159         long    acl_size;
 160 
 161         if ((acl_info == NULL) || (*acl_info->attr_info == '\0'))
 162                 return (0);
 163 
 164         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 165             &actual_size, TRUE, local_commands);
 166         if (!tar_hdr)
 167                 return (0);
 168 
 169         tar_hdr->th_linkflag = LF_ACL;
 170         acl_info->attr_type = UFSD_ACL;
 171         (void) snprintf(acl_info->attr_len, sizeof (acl_info->attr_len),
 172             "%06o", strlen(acl_info->attr_info));
 173 
 174         acl_size = sizeof (*acl_info);
 175         (void) strlcpy(tar_hdr->th_name, "UFSACL", TLM_NAME_SIZE);
 176         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 177             acl_size);
 178         (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
 179             0444);
 180         (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ", 0);
 181         (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ", 0);
 182         (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
 183             "%011o ", 0);
 184         (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 185             sizeof (tar_hdr->th_magic));
 186 
 187         tlm_build_header_checksum(tar_hdr);
 188 
 189         (void) output_mem(local_commands, (void *)acl_info, acl_size);
 190         return (0);
 191 }
 192 
 193 /*
 194  * output_humongus_header
 195  *
 196  * output a special header record for HUGE files
 197  * output is:   1) a TAR "HUGE" header redord
 198  *              2) a "file" of size, name
 199  */
 200 static int
 201 output_humongus_header(char *fullname, longlong_t file_size,
 202     tlm_cmd_t *local_commands)
 203 {
 204         char    *buf;
 205         int     len;
 206         long    actual_size;
 207         tlm_tar_hdr_t *tar_hdr;
 208 
 209         /*
 210          * buf will contain: "%llu %s":
 211          * - 20 is the maximum length of 'ulong_tlong' decimal notation.
 212          * - The first '1' is for the ' ' between the "%llu" and the fullname.
 213          * - The last '1' is for the null-terminator of fullname.
 214          */
 215         len = 20 + 1 + strlen(fullname) + 1;
 216 
 217         if ((buf = ndmp_malloc(sizeof (char) * len)) == NULL)
 218                 return (-1);
 219 
 220         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 221             &actual_size, TRUE, local_commands);
 222         if (!tar_hdr) {
 223                 free(buf);
 224                 return (0);
 225         }
 226 
 227         tar_hdr->th_linkflag = LF_HUMONGUS;
 228         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 229             len);
 230         tlm_build_header_checksum(tar_hdr);
 231         (void) snprintf(buf, len, "%lld %s", file_size, fullname);
 232         (void) output_mem(local_commands, buf, len);
 233 
 234         free(buf);
 235         return (0);
 236 }
 237 
 238 
 239 /*
 240  * output_xattr_header
 241  *
 242  * output the TAR header record for extended attributes
 243  */
 244 static int
 245 output_xattr_header(char *fname, char *aname, int fd,
 246     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
 247 {
 248         struct stat64 *attr = &tlm_acls->acl_attr;
 249         struct xattr_hdr *xhdr;
 250         struct xattr_buf *xbuf;
 251         tlm_tar_hdr_t *tar_hdr;
 252         long    actual_size;
 253         char    *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
 254         int     hsize;
 255         int     comlen;
 256         int     namesz;
 257 
 258         if (section_name == NULL)
 259                 return (-TLM_NO_SCRATCH_SPACE);
 260 
 261         if (fstat64(fd, attr) == -1) {
 262                 syslog(LOG_ERR, "output_file_header stat failed.");
 263                 free(section_name);
 264                 return (-TLM_OPEN_ERR);
 265         }
 266 
 267         /*
 268          * if the file has to go out in sections,
 269          * we must mung the name.
 270          */
 271         if (section == 0) {
 272                 (void) snprintf(section_name, TLM_MAX_PATH_NAME,
 273                     "/dev/null/%s.hdr", aname);
 274         } else {
 275                 (void) snprintf(section_name,
 276                     TLM_MAX_PATH_NAME, "%s.%03d", aname, section);
 277         }
 278         namesz = strlen(section_name) + strlen(fname) + 2; /* 2 nulls */
 279         hsize = namesz + sizeof (struct xattr_hdr) + sizeof (struct xattr_buf);
 280         comlen = namesz + sizeof (struct xattr_buf);
 281 
 282         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 283             &actual_size, TRUE, local_commands);
 284         if (!tar_hdr) {
 285                 free(section_name);
 286                 return (0);
 287         }
 288 
 289         (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
 290 
 291         tar_hdr->th_linkflag = LF_XATTR;
 292         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 293             hsize);
 294         (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
 295             attr->st_mode & 07777);
 296         (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
 297             attr->st_uid);
 298         (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
 299             attr->st_gid);
 300         (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
 301             attr->st_mtime);
 302         (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 303             sizeof (tar_hdr->th_magic));
 304 
 305         tlm_build_header_checksum(tar_hdr);
 306 
 307         xhdr = (struct xattr_hdr *)get_write_buffer(RECORDSIZE,
 308             &actual_size, TRUE, local_commands);
 309         if (!xhdr) {
 310                 free(section_name);
 311                 return (0);
 312         }
 313 
 314         (void) snprintf(xhdr->h_version, sizeof (xhdr->h_version), "%s",
 315             XATTR_ARCH_VERS);
 316         (void) snprintf(xhdr->h_size, sizeof (xhdr->h_size), "%0*d",
 317             sizeof (xhdr->h_size) - 1, hsize);
 318         (void) snprintf(xhdr->h_component_len, sizeof (xhdr->h_component_len),
 319             "%0*d", sizeof (xhdr->h_component_len) - 1, comlen);
 320         (void) snprintf(xhdr->h_link_component_len,
 321             sizeof (xhdr->h_link_component_len), "%0*d",
 322             sizeof (xhdr->h_link_component_len) - 1, 0);
 323 
 324         xbuf = (struct xattr_buf *)(((caddr_t)xhdr) +
 325             sizeof (struct xattr_hdr));
 326         (void) snprintf(xbuf->h_namesz, sizeof (xbuf->h_namesz), "%0*d",
 327             sizeof (xbuf->h_namesz) - 1, namesz);
 328 
 329         /* No support for links in extended attributes */
 330         xbuf->h_typeflag = LF_NORMAL;
 331 
 332         (void) strlcpy(xbuf->h_names, fname, TLM_NAME_SIZE);
 333         (void) strlcpy(&xbuf->h_names[strlen(fname) + 1], aname,
 334             TLM_NAME_SIZE);
 335 
 336         free(section_name);
 337         return (0);
 338 }
 339 
 340 
 341 /*
 342  * output_file_header
 343  *
 344  * output the TAR header record
 345  */
 346 static int
 347 output_file_header(char *name, char *link,
 348     tlm_acls_t *tlm_acls, int section, tlm_cmd_t *local_commands)
 349 {
 350         static  longlong_t file_count = 0;
 351         struct stat64 *attr = &tlm_acls->acl_attr;
 352         tlm_tar_hdr_t *tar_hdr;
 353         long    actual_size;
 354         boolean_t long_name = FALSE;
 355         boolean_t long_link = FALSE;
 356         char    *section_name = ndmp_malloc(TLM_MAX_PATH_NAME);
 357         int     nmlen, lnklen;
 358         uid_t uid;
 359         gid_t gid;
 360         char *uname = "";
 361         char *gname = "";
 362         struct passwd *pwd;
 363         struct group *grp;
 364 
 365         if (section_name == NULL)
 366                 return (-TLM_NO_SCRATCH_SPACE);
 367 
 368         /*
 369          * if the file has to go out in sections,
 370          * we must mung the name.
 371          */
 372         if (section == 0) {
 373                 (void) strlcpy(section_name, name, TLM_MAX_PATH_NAME);
 374         } else {
 375                 (void) snprintf(section_name,
 376                     TLM_MAX_PATH_NAME, "%s.%03d", name, section);
 377         }
 378 
 379         if ((pwd = getpwuid(attr->st_uid)) != NULL)
 380                 uname = pwd->pw_name;
 381         if ((grp = getgrgid(attr->st_gid)) != NULL)
 382                 gname = grp->gr_name;
 383 
 384         if ((ulong_t)(uid = attr->st_uid) > (ulong_t)OCTAL7CHAR)
 385                 uid = UID_NOBODY;
 386         if ((ulong_t)(gid = attr->st_gid) > (ulong_t)OCTAL7CHAR)
 387                 gid = GID_NOBODY;
 388 
 389         nmlen = strlen(section_name);
 390         if (nmlen >= NAMSIZ) {
 391                 /*
 392                  * file name is too big, it must go out
 393                  * in its own data file
 394                  */
 395                 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 396                     &actual_size, TRUE, local_commands);
 397                 if (!tar_hdr) {
 398                         free(section_name);
 399                         return (0);
 400                 }
 401                 (void) snprintf(tar_hdr->th_name,
 402                     sizeof (tar_hdr->th_name),
 403                     "%s%08qd.fil",
 404                     LONGNAME_PREFIX,
 405                     file_count++);
 406 
 407                 tar_hdr->th_linkflag = LF_LONGNAME;
 408                 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
 409                     "%011o ", nmlen);
 410                 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
 411                     "%06o ", attr->st_mode & 07777);
 412                 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
 413                     "%06o ", uid);
 414                 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
 415                     "%06o ", gid);
 416                 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
 417                     "%.31s", uname);
 418                 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
 419                     "%.31s", gname);
 420                 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
 421                     "%011o ", attr->st_mtime);
 422                 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 423                     sizeof (tar_hdr->th_magic));
 424 
 425                 tlm_build_header_checksum(tar_hdr);
 426 
 427                 (void) output_mem(local_commands,
 428                     (void *)section_name, nmlen);
 429                 long_name = TRUE;
 430         }
 431 
 432         lnklen = strlen(link);
 433         if (lnklen >= NAMSIZ) {
 434                 /*
 435                  * link name is too big, it must go out
 436                  * in its own data file
 437                  */
 438                 tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 439                     &actual_size, TRUE, local_commands);
 440                 if (!tar_hdr) {
 441                         free(section_name);
 442                         return (0);
 443                 }
 444                 (void) snprintf(tar_hdr->th_linkname,
 445                     sizeof (tar_hdr->th_name),
 446                     "%s%08qd.slk",
 447                     LONGNAME_PREFIX,
 448                     file_count++);
 449 
 450                 tar_hdr->th_linkflag = LF_LONGLINK;
 451                 (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size),
 452                     "%011o ", lnklen);
 453                 (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode),
 454                     "%06o ", attr->st_mode & 07777);
 455                 (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid),
 456                     "%06o ", uid);
 457                 (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid),
 458                     "%06o ", gid);
 459                 (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname),
 460                     "%.31s", uname);
 461                 (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname),
 462                     "%.31s", gname);
 463                 (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime),
 464                     "%011o ", attr->st_mtime);
 465                 (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 466                     sizeof (tar_hdr->th_magic));
 467 
 468                 tlm_build_header_checksum(tar_hdr);
 469 
 470                 (void) output_mem(local_commands, (void *)link,
 471                     lnklen);
 472                 long_link = TRUE;
 473         }
 474         tar_hdr = (tlm_tar_hdr_t *)get_write_buffer(RECORDSIZE,
 475             &actual_size, TRUE, local_commands);
 476         if (!tar_hdr) {
 477                 free(section_name);
 478                 return (0);
 479         }
 480         if (long_name) {
 481                 (void) snprintf(tar_hdr->th_name,
 482                     sizeof (tar_hdr->th_name),
 483                     "%s%08qd.fil",
 484                     LONGNAME_PREFIX,
 485                     file_count++);
 486         } else {
 487                 (void) strlcpy(tar_hdr->th_name, section_name, TLM_NAME_SIZE);
 488         }
 489 
 490         if (long_link) {
 491                 (void) snprintf(tar_hdr->th_linkname,
 492                     sizeof (tar_hdr->th_name),
 493                     "%s%08qd.slk",
 494                     LONGNAME_PREFIX,
 495                     file_count++);
 496         } else {
 497                 (void) strlcpy(tar_hdr->th_linkname, link, TLM_NAME_SIZE);
 498         }
 499         switch (attr->st_mode & S_IFMT) {
 500         case S_IFDIR:
 501                 tar_hdr->th_linkflag = LF_DIR;
 502                 break;
 503         case S_IFIFO:
 504                 tar_hdr->th_linkflag = LF_FIFO;
 505                 break;
 506         case S_IFBLK:
 507         case S_IFCHR:
 508                 if (S_ISBLK(attr->st_mode))
 509                         tar_hdr->th_linkflag = LF_BLK;
 510                 else
 511                         tar_hdr->th_linkflag = LF_CHR;
 512                 (void) snprintf(tar_hdr->th_shared.th_dev.th_devmajor,
 513                     sizeof (tar_hdr->th_shared.th_dev.th_devmajor), "%06o ",
 514                     major(attr->st_rdev));
 515                 (void) snprintf(tar_hdr->th_shared.th_dev.th_devminor,
 516                     sizeof (tar_hdr->th_shared.th_dev.th_devminor), "%06o ",
 517                     minor(attr->st_rdev));
 518                 break;
 519         default:
 520                 if (attr->st_nlink > 1) {
 521                         /* mark file with hardlink LF_LINK */
 522                         tar_hdr->th_linkflag = LF_LINK;
 523                         (void) snprintf(tar_hdr->th_shared.th_hlink_ino,
 524                             sizeof (tar_hdr->th_shared.th_hlink_ino),
 525                             "%011llo ", attr->st_ino);
 526                 } else {
 527                         tar_hdr->th_linkflag = *link == 0 ? LF_NORMAL :
 528                             LF_SYMLINK;
 529                 }
 530         }
 531         (void) snprintf(tar_hdr->th_size, sizeof (tar_hdr->th_size), "%011o ",
 532             (long)attr->st_size);
 533         (void) snprintf(tar_hdr->th_mode, sizeof (tar_hdr->th_mode), "%06o ",
 534             attr->st_mode & 07777);
 535         (void) snprintf(tar_hdr->th_uid, sizeof (tar_hdr->th_uid), "%06o ",
 536             uid);
 537         (void) snprintf(tar_hdr->th_gid, sizeof (tar_hdr->th_gid), "%06o ",
 538             gid);
 539         (void) snprintf(tar_hdr->th_uname, sizeof (tar_hdr->th_uname), "%.31s",
 540             uname);
 541         (void) snprintf(tar_hdr->th_gname, sizeof (tar_hdr->th_gname), "%.31s",
 542             gname);
 543         (void) snprintf(tar_hdr->th_mtime, sizeof (tar_hdr->th_mtime), "%011o ",
 544             attr->st_mtime);
 545         (void) strlcpy(tar_hdr->th_magic, TLM_MAGIC,
 546             sizeof (tar_hdr->th_magic));
 547 
 548         tlm_build_header_checksum(tar_hdr);
 549         if (long_name || long_link) {
 550                 if (file_count > 99999990) {
 551                         file_count = 0;
 552                 }
 553         }
 554         free(section_name);
 555         return (0);
 556 }
 557 
 558 
 559 /*
 560  * tlm_readlink
 561  *
 562  * Read where the softlink points to.  Read the link in the checkpointed
 563  * path if the backup is being done on a checkpointed file system.
 564  */
 565 static int
 566 tlm_readlink(char *nm, char *snap, char *buf, int bufsize)
 567 {
 568         int len;
 569 
 570         if ((len = readlink(snap, buf, bufsize)) >= 0) {
 571                 /*
 572                  * realink(2) doesn't null terminate the link name.  We must
 573                  * do it here.
 574                  */
 575                 buf[len] = '\0';
 576         } else {
 577                 syslog(LOG_ERR, "Error %d reading softlink of [%s]",
 578                     errno, nm);
 579                 buf[0] = '\0';
 580 
 581                 /* Backup the link if the destination missing */
 582                 if (errno == ENOENT)
 583                         return (0);
 584 
 585         }
 586 
 587         return (len);
 588 }
 589 
 590 /*
 591  * Read the system attribute file in a single buffer to write
 592  * it as a single write. A partial write to system attribute would
 593  * cause an EINVAL on write.
 594  */
 595 static char *
 596 get_write_one_buf(char *buf, char *rec, int buf_size, int rec_size,
 597     tlm_cmd_t *lc)
 598 {
 599         int len;
 600         long write_size;
 601 
 602         if (rec_size > buf_size)
 603                 return (rec);
 604 
 605         len = rec_size;
 606         (void) memcpy(rec, buf, len);
 607         buf += len;
 608         while (rec_size < buf_size) {
 609                 rec = get_write_buffer(buf_size - rec_size,
 610                     &write_size, FALSE, lc);
 611                 if (!rec)
 612                         return (0);
 613 
 614                 len = min(buf_size - rec_size, write_size);
 615                 (void) memcpy(rec, buf, len);
 616                 rec_size += len;
 617                 buf += len;
 618         }
 619         return (rec);
 620 }
 621 
 622 
 623 /*
 624  * tlm_output_xattr
 625  *
 626  * Put this file into the output buffers.
 627  */
 628 /*ARGSUSED*/
 629 longlong_t
 630 tlm_output_xattr(char  *dir, char *name, char *chkdir,
 631     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
 632     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats)
 633 {
 634         char    *fullname;              /* directory + name */
 635         char    *snapname;              /* snapshot name */
 636         int     section;                /* section of a huge file */
 637         int     fd;
 638         int     afd = 0;
 639         longlong_t seek_spot = 0;       /* location in the file */
 640                                         /* for Multi Volume record */
 641         DIR *dp;
 642         struct dirent *dtp;
 643         char *attrname;
 644         char *fnamep;
 645         int rv = 0;
 646 
 647         if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
 648                 return (TLM_NO_SOURCE_FILE);
 649         }
 650 
 651         fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
 652         if (fullname == NULL) {
 653                 free(fullname);
 654                 return (-TLM_NO_SCRATCH_SPACE);
 655         }
 656 
 657         if (!tlm_cat_path(fullname, dir, name)) {
 658                 syslog(LOG_ERR, "Path too long.");
 659                 free(fullname);
 660                 return (-TLM_NO_SCRATCH_SPACE);
 661         }
 662 
 663         if (pathconf(fullname, _PC_XATTR_EXISTS) != 1 &&
 664             sysattr_support(fullname, _PC_SATTR_EXISTS) != 1) {
 665                 free(fullname);
 666                 return (0);
 667         }
 668 
 669         attrname = ndmp_malloc(TLM_MAX_PATH_NAME);
 670         snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
 671         if (attrname == NULL || snapname == NULL) {
 672                 rv = -TLM_NO_SCRATCH_SPACE;
 673                 goto err_out;
 674         }
 675 
 676         if (!tlm_cat_path(snapname, chkdir, name)) {
 677                 syslog(LOG_ERR, "Path too long.");
 678                 rv = -TLM_NO_SCRATCH_SPACE;
 679                 goto err_out;
 680         }
 681 
 682         fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
 683 
 684         /*
 685          * Open the file for reading.
 686          */
 687         fd = attropen(fnamep, ".", O_RDONLY);
 688         if (fd == -1) {
 689                 syslog(LOG_ERR, "BACKUP> Can't open file [%s][%s]",
 690                     fullname, fnamep);
 691                 rv = TLM_NO_SOURCE_FILE;
 692                 goto err_out;
 693         }
 694 
 695         section = 0;
 696 
 697         dp = (DIR *)fdopendir(fd);
 698         if (dp == NULL) {
 699                 syslog(LOG_ERR, "BACKUP> Can't open file [%s]", fullname);
 700                 (void) close(fd);
 701                 rv = TLM_NO_SOURCE_FILE;
 702                 goto err_out;
 703         }
 704 
 705         while ((dtp = readdir(dp)) != NULL) {
 706                 int section_size;
 707 
 708                 if (*dtp->d_name == '.')
 709                         continue;
 710 
 711                 if (sysattr_rdonly(dtp->d_name))
 712                         continue;
 713 
 714                 afd = attropen(fnamep, dtp->d_name, O_RDONLY);
 715                 if (afd == -1) {
 716                         syslog(LOG_ERR,
 717                             "problem(%d) opening xattr file [%s][%s]", errno,
 718                             fullname, fnamep);
 719                         goto tear_down;
 720                 }
 721 
 722                 (void) output_xattr_header(fullname, dtp->d_name, afd,
 723                     tlm_acls, section, local_commands);
 724                 (void) snprintf(attrname, TLM_MAX_PATH_NAME, "/dev/null/%s",
 725                     dtp->d_name);
 726                 (void) output_file_header(attrname, "", tlm_acls, 0,
 727                     local_commands);
 728 
 729                 section_size = (long)llmin(tlm_acls->acl_attr.st_size,
 730                     (longlong_t)TLM_MAX_TAR_IMAGE);
 731 
 732                 /* We only can read upto one section extended attribute */
 733                 while (section_size > 0) {
 734                         char    *buf;
 735                         long    actual_size;
 736                         int     read_size;
 737                         int sysattr_read = 0;
 738                         char *rec = NULL;
 739                         int size = 0;
 740 
 741                         /*
 742                          * check for Abort commands
 743                          */
 744                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
 745                                 local_commands->tc_writer = TLM_ABORT;
 746                                 goto tear_down;
 747                         }
 748 
 749                         local_commands->tc_buffers->tbs_buffer[
 750                             local_commands->tc_buffers->tbs_buffer_in].
 751                             tb_file_size = section_size;
 752                         local_commands->tc_buffers->tbs_buffer[
 753                             local_commands->tc_buffers->tbs_buffer_in].
 754                             tb_seek_spot = seek_spot;
 755 
 756                         buf = get_write_buffer(section_size,
 757                             &actual_size, FALSE, local_commands);
 758                         if (!buf)
 759                                 goto tear_down;
 760 
 761                         if ((actual_size < section_size) &&
 762                             sysattr_rw(dtp->d_name)) {
 763                                 rec = buf;
 764                                 buf = ndmp_malloc(section_size);
 765                                 if (!buf)
 766                                         goto tear_down;
 767                                 size = actual_size;
 768                                 actual_size = section_size;
 769                                 sysattr_read = 1;
 770                         }
 771 
 772                         /*
 773                          * check for Abort commands
 774                          */
 775                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
 776                                 local_commands->tc_writer = TLM_ABORT;
 777                                 goto tear_down;
 778                         }
 779 
 780                         read_size = min(section_size, actual_size);
 781                         if ((actual_size = read(afd, buf, read_size)) < 0)
 782                                 break;
 783 
 784                         if (sysattr_read) {
 785                                 if (get_write_one_buf(buf, rec, read_size,
 786                                     size, local_commands) == 0) {
 787                                         free(buf);
 788                                         goto tear_down;
 789                                 }
 790                                 free(buf);
 791                         }
 792 
 793 
 794                         NS_ADD(rdisk, actual_size);
 795                         NS_INC(rfile);
 796 
 797                         if (actual_size == -1) {
 798                                 syslog(LOG_ERR,
 799                                     "problem(%d) reading file [%s][%s]",
 800                                     errno, fullname, snapname);
 801                                 goto tear_down;
 802                         }
 803                         seek_spot += actual_size;
 804                         section_size -= actual_size;
 805                 }
 806                 (void) close(afd);
 807                 afd = -1;
 808         }
 809 
 810 tear_down:
 811         local_commands->tc_buffers->tbs_buffer[
 812             local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
 813 
 814         if (afd > 0)
 815                 (void) close(afd);
 816 
 817         /* closedir closes fd too */
 818         (void) closedir(dp);
 819 
 820 err_out:
 821         free(fullname);
 822         free(attrname);
 823         free(snapname);
 824         return (rv);
 825 }
 826 
 827 
 828 /*
 829  * tlm_output_file
 830  *
 831  * Put this file into the output buffers.
 832  */
 833 longlong_t
 834 tlm_output_file(char *dir, char *name, char *chkdir,
 835     tlm_acls_t *tlm_acls, tlm_commands_t *commands, tlm_cmd_t *local_commands,
 836     tlm_job_stats_t *job_stats, struct hardlink_q *hardlink_q)
 837 {
 838         char    *fullname;              /* directory + name */
 839         char    *snapname;              /* snapshot name */
 840         char    *linkname;              /* where this file points */
 841         int     section = 0;            /* section of a huge file */
 842         int     fd;
 843         longlong_t real_size;           /* the origional file size */
 844         longlong_t file_size;           /* real size of this file */
 845         longlong_t seek_spot = 0;       /* location in the file */
 846                                         /* for Multi Volume record */
 847         u_longlong_t pos;
 848         char *fnamep;
 849 
 850         /* Indicate whether a file with the same inode has been backed up. */
 851         int hardlink_done = 0;
 852 
 853         /*
 854          * If a file with the same inode has been backed up, hardlink_pos holds
 855          * the tape offset of the data record.
 856          */
 857         u_longlong_t hardlink_pos = 0;
 858 
 859         if (tlm_is_too_long(tlm_acls->acl_checkpointed, dir, name)) {
 860                 syslog(LOG_ERR, "Path too long [%s][%s]", dir, name);
 861                 return (-TLM_NO_SCRATCH_SPACE);
 862         }
 863 
 864         fullname = ndmp_malloc(TLM_MAX_PATH_NAME);
 865         linkname = ndmp_malloc(TLM_MAX_PATH_NAME);
 866         snapname = ndmp_malloc(TLM_MAX_PATH_NAME);
 867         if (fullname == NULL || linkname == NULL || snapname == NULL) {
 868                 real_size = -TLM_NO_SCRATCH_SPACE;
 869                 goto err_out;
 870         }
 871         if (!tlm_cat_path(fullname, dir, name) ||
 872             !tlm_cat_path(snapname, chkdir, name)) {
 873                 syslog(LOG_ERR, "Path too long.");
 874                 real_size = -TLM_NO_SCRATCH_SPACE;
 875                 goto err_out;
 876         }
 877 
 878         pos = tlm_get_data_offset(local_commands);
 879 
 880         if (S_ISPECIAL(tlm_acls->acl_attr.st_mode)) {
 881                 if (S_ISLNK(tlm_acls->acl_attr.st_mode)) {
 882                         file_size = tlm_readlink(fullname, snapname, linkname,
 883                             TLM_MAX_PATH_NAME-1);
 884                         if (file_size < 0) {
 885                                 real_size = -ENOENT;
 886                                 goto err_out;
 887                         }
 888                 }
 889 
 890                 /*
 891                  * Since soft links can not be read(2), we should only
 892                  * backup the file header.
 893                  */
 894                 (void) output_file_header(fullname,
 895                     linkname,
 896                     tlm_acls,
 897                     section,
 898                     local_commands);
 899 
 900                 (void) tlm_log_fhnode(job_stats, dir, name,
 901                     &tlm_acls->acl_attr, pos);
 902                 (void) tlm_log_fhpath_name(job_stats, fullname,
 903                     &tlm_acls->acl_attr, pos);
 904 
 905                 free(fullname);
 906                 free(linkname);
 907                 free(snapname);
 908                 return (0);
 909         }
 910 
 911         fnamep = (tlm_acls->acl_checkpointed) ? snapname : fullname;
 912 
 913         /*
 914          * For hardlink, only read the data if no other link
 915          * belonging to the same inode has been backed up.
 916          */
 917         if (tlm_acls->acl_attr.st_nlink > 1) {
 918                 hardlink_done = !hardlink_q_get(hardlink_q,
 919                     tlm_acls->acl_attr.st_ino, &hardlink_pos, NULL);
 920         }
 921 
 922         if (!hardlink_done) {
 923                 /*
 924                  * Open the file for reading.
 925                  */
 926                 fd = open(fnamep, O_RDONLY);
 927                 if (fd == -1) {
 928                         syslog(LOG_ERR,
 929                             "BACKUP> Can't open file [%s][%s] err(%d)",
 930                             fullname, fnamep, errno);
 931                         real_size = -TLM_NO_SOURCE_FILE;
 932                         goto err_out;
 933                 }
 934         } else {
 935                 syslog(LOG_DEBUG, "found hardlink, inode = %llu, pos = %llu ",
 936                     tlm_acls->acl_attr.st_ino, hardlink_pos);
 937 
 938                 fd = -1;
 939         }
 940 
 941         linkname[0] = 0;
 942 
 943         real_size = tlm_acls->acl_attr.st_size;
 944         (void) output_acl_header(&tlm_acls->acl_info,
 945             local_commands);
 946 
 947         /*
 948          * section = 0: file is small enough for TAR
 949          * section > 0: file goes out in TLM_MAX_TAR_IMAGE sized chunks
 950          *              and the file name gets munged
 951          */
 952         file_size = real_size;
 953         if (file_size > TLM_MAX_TAR_IMAGE) {
 954                 if (output_humongus_header(fullname, file_size,
 955                     local_commands) < 0) {
 956                         (void) close(fd);
 957                         real_size = -TLM_NO_SCRATCH_SPACE;
 958                         goto err_out;
 959                 }
 960                 section = 1;
 961         } else {
 962                 section = 0;
 963         }
 964 
 965         /*
 966          * For hardlink, if other link belonging to the same inode
 967          * has been backed up, only backup an empty record.
 968          */
 969         if (hardlink_done)
 970                 file_size = 0;
 971 
 972         /*
 973          * work
 974          */
 975         if (file_size == 0) {
 976                 (void) output_file_header(fullname,
 977                     linkname,
 978                     tlm_acls,
 979                     section,
 980                     local_commands);
 981                 /*
 982                  * this can fall right through since zero size files
 983                  * will be skipped by the WHILE loop anyway
 984                  */
 985         }
 986 
 987         while (file_size > 0) {
 988                 int section_size = llmin(file_size,
 989                     (longlong_t)TLM_MAX_TAR_IMAGE);
 990 
 991                 tlm_acls->acl_attr.st_size = (longlong_t)section_size;
 992                 (void) output_file_header(fullname,
 993                     linkname,
 994                     tlm_acls,
 995                     section,
 996                     local_commands);
 997                 while (section_size > 0) {
 998                         char    *buf;
 999                         long    actual_size;
1000                         int     read_size;
1001 
1002                         /*
1003                          * check for Abort commands
1004                          */
1005                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
1006                                 local_commands->tc_writer = TLM_ABORT;
1007                                 goto tear_down;
1008                         }
1009 
1010                         local_commands->tc_buffers->tbs_buffer[
1011                             local_commands->tc_buffers->tbs_buffer_in].
1012                             tb_file_size = section_size;
1013                         local_commands->tc_buffers->tbs_buffer[
1014                             local_commands->tc_buffers->tbs_buffer_in].
1015                             tb_seek_spot = seek_spot;
1016 
1017                         buf = get_write_buffer(section_size,
1018                             &actual_size, FALSE, local_commands);
1019                         if (!buf)
1020                                 goto tear_down;
1021 
1022                         /*
1023                          * check for Abort commands
1024                          */
1025                         if (commands->tcs_reader != TLM_BACKUP_RUN) {
1026                                 local_commands->tc_writer = TLM_ABORT;
1027                                 goto tear_down;
1028                         }
1029 
1030                         read_size = min(section_size, actual_size);
1031                         actual_size = read(fd, buf, read_size);
1032                         NS_ADD(rdisk, actual_size);
1033                         NS_INC(rfile);
1034 
1035                         if (actual_size == 0)
1036                                 break;
1037 
1038                         if (actual_size == -1) {
1039                                 syslog(LOG_ERR,
1040                                     "problem(%d) reading file [%s][%s]",
1041                                     errno, fullname, snapname);
1042                                 goto tear_down;
1043                         }
1044                         seek_spot += actual_size;
1045                         file_size -= actual_size;
1046                         section_size -= actual_size;
1047                 }
1048                 section++;
1049         }
1050 
1051         /*
1052          * If data belonging to this hardlink has been backed up, add the link
1053          * to hardlink queue.
1054          */
1055         if (tlm_acls->acl_attr.st_nlink > 1 && !hardlink_done) {
1056                 (void) hardlink_q_add(hardlink_q, tlm_acls->acl_attr.st_ino,
1057                     pos, NULL, 0);
1058                 syslog(LOG_DEBUG,
1059                     "backed up hardlink file %s, inode = %llu, pos = %llu ",
1060                     fullname, tlm_acls->acl_attr.st_ino, pos);
1061         }
1062 
1063         /*
1064          * For hardlink, if other link belonging to the same inode has been
1065          * backed up, no add_node entry should be sent for this link.
1066          */
1067         if (hardlink_done) {
1068                 syslog(LOG_DEBUG,
1069                     "backed up hardlink link %s, inode = %llu, pos = %llu ",
1070                     fullname, tlm_acls->acl_attr.st_ino, hardlink_pos);
1071         } else {
1072                 (void) tlm_log_fhnode(job_stats, dir, name,
1073                     &tlm_acls->acl_attr, pos);
1074         }
1075 
1076         (void) tlm_log_fhpath_name(job_stats, fullname, &tlm_acls->acl_attr,
1077             pos);
1078 
1079 tear_down:
1080         local_commands->tc_buffers->tbs_buffer[
1081             local_commands->tc_buffers->tbs_buffer_in].tb_seek_spot = 0;
1082 
1083         (void) close(fd);
1084 
1085 err_out:
1086         free(fullname);
1087         free(linkname);
1088         free(snapname);
1089         return (real_size);
1090 }
1091 
1092 /*
1093  * tar_putfile
1094  *
1095  * Main file backup function for tar
1096  */
1097 int
1098 tar_putfile(char *dir, char *name, char *chkdir,
1099     tlm_acls_t *tlm_acls, tlm_commands_t *commands,
1100     tlm_cmd_t *local_commands, tlm_job_stats_t *job_stats,
1101     struct hardlink_q *hardlink_q)
1102 {
1103         int rv;
1104 
1105         rv = tlm_output_file(dir, name, chkdir, tlm_acls, commands,
1106             local_commands, job_stats, hardlink_q);
1107         if (rv < 0)
1108                 return (rv);
1109 
1110         rv = tlm_output_xattr(dir, name, chkdir, tlm_acls, commands,
1111             local_commands, job_stats);
1112 
1113         return (rv < 0 ? rv : 0);
1114 }
1115 
1116 /*
1117  * get_write_buffer
1118  *
1119  * a wrapper to tlm_get_write_buffer so that
1120  * we can cleanly detect ABORT commands
1121  * without involving the TLM library with
1122  * our problems.
1123  */
1124 static char *
1125 get_write_buffer(long size, long *actual_size,
1126     boolean_t zero, tlm_cmd_t *local_commands)
1127 {
1128         while (local_commands->tc_reader == TLM_BACKUP_RUN) {
1129                 char *rec = tlm_get_write_buffer(size, actual_size,
1130                     local_commands->tc_buffers, zero);
1131                 if (rec != 0) {
1132                         return (rec);
1133                 }
1134         }
1135         return (NULL);
1136 }
1137 
1138 #define NDMP_MORE_RECORDS       2
1139 
1140 /*
1141  * write_tar_eof
1142  *
1143  * This function is initially written for NDMP support.  It appends
1144  * two tar headers to the tar file, and also N more empty buffers
1145  * to make sure that the two tar headers will be read as a part of
1146  * a mover record and don't get locked because of EOM on the mover
1147  * side.
1148  */
1149 void
1150 write_tar_eof(tlm_cmd_t *local_commands)
1151 {
1152         int i;
1153         long actual_size;
1154         tlm_buffers_t *bufs;
1155 
1156         /*
1157          * output 2 zero filled records,
1158          * TAR wants this.
1159          */
1160         (void) get_write_buffer(sizeof (tlm_tar_hdr_t),
1161             &actual_size, TRUE, local_commands);
1162         (void) get_write_buffer(sizeof (tlm_tar_hdr_t),
1163             &actual_size, TRUE, local_commands);
1164 
1165         /*
1166          * NDMP: Clear the rest of the buffer and write two more buffers
1167          * to the tape.
1168          */
1169         bufs = local_commands->tc_buffers;
1170         (void) get_write_buffer(bufs->tbs_data_transfer_size,
1171             &actual_size, TRUE, local_commands);
1172 
1173         for (i = 0; i < NDMP_MORE_RECORDS &&
1174             local_commands->tc_reader == TLM_BACKUP_RUN; i++) {
1175                 /*
1176                  * We don't need the return value of get_write_buffer(),
1177                  * since it's already zeroed out if the buffer is returned.
1178                  */
1179                 (void) get_write_buffer(bufs->tbs_data_transfer_size,
1180                     &actual_size, TRUE, local_commands);
1181         }
1182 
1183         bufs->tbs_buffer[bufs->tbs_buffer_in].tb_full = TRUE;
1184         tlm_buffer_release_in_buf(bufs);
1185 }
1186 
1187 /*
1188  * Callback to backup each ZFS property
1189  */
1190 static int
1191 zfs_put_prop_cb(int prop, void *pp)
1192 {
1193         ndmp_metadata_handle_t *mhd;
1194         ndmp_metadata_header_ext_t *mhp;
1195         ndmp_metadata_property_ext_t *mpp;
1196         char vbuf[ZFS_MAXPROPLEN];
1197         char sbuf[ZFS_MAXPROPLEN];
1198         zprop_source_t stype;
1199         char *sourcestr;
1200 
1201         if (pp == NULL)
1202                 return (ZPROP_INVAL);
1203 
1204         mhd = (ndmp_metadata_handle_t *)pp;
1205         mhp = mhd->ml_xhdr;
1206         mpp = &mhp->nh_property[mhp->nh_count];
1207 
1208         if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
1209             sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
1210                 return (ZPROP_INVAL);
1211 
1212         if (zfs_prop_get(mhd->ml_handle, prop, vbuf, sizeof (vbuf),
1213             &stype, sbuf, sizeof (sbuf), B_TRUE) != 0) {
1214                 mhp->nh_count++;
1215                 return (ZPROP_CONT);
1216         }
1217 
1218         (void) strlcpy(mpp->mp_name, zfs_prop_to_name(prop),
1219             ZFS_MAX_DATASET_NAME_LEN);
1220         (void) strlcpy(mpp->mp_value, vbuf, ZFS_MAXPROPLEN);
1221 
1222         switch (stype) {
1223         case ZPROP_SRC_NONE:
1224                 sourcestr = "none";
1225                 break;
1226         case ZPROP_SRC_RECEIVED:
1227                 sourcestr = "received";
1228                 break;
1229         case ZPROP_SRC_LOCAL:
1230                 sourcestr = mhp->nh_dataset;
1231                 break;
1232         case ZPROP_SRC_TEMPORARY:
1233                 sourcestr = "temporary";
1234                 break;
1235         case ZPROP_SRC_DEFAULT:
1236                 sourcestr = "default";
1237                 break;
1238         default:
1239                 sourcestr = sbuf;
1240                 break;
1241         }
1242         (void) strlcpy(mpp->mp_source, sourcestr, ZFS_MAXPROPLEN);
1243 
1244         mhp->nh_count++;
1245         return (ZPROP_CONT);
1246 }
1247 
1248 /*
1249  * Callback to backup each ZFS user/group quota
1250  */
1251 static int
1252 zfs_put_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
1253 {
1254         ndmp_metadata_handle_t *mhd;
1255         ndmp_metadata_header_ext_t *mhp;
1256         ndmp_metadata_property_ext_t *mpp;
1257         char *typestr;
1258 
1259         if (pp == NULL)
1260                 return (ZPROP_INVAL);
1261 
1262         mhd = (ndmp_metadata_handle_t *)pp;
1263         mhp = mhd->ml_xhdr;
1264         mpp = &mhp->nh_property[mhp->nh_count];
1265 
1266         if (mhp->nh_count * sizeof (ndmp_metadata_property_ext_t) +
1267             sizeof (ndmp_metadata_header_ext_t) > mhp->nh_total_bytes)
1268                 return (ZPROP_INVAL);
1269 
1270         if (mhd->ml_quota_prop == ZFS_PROP_USERQUOTA)
1271                 typestr = "userquota";
1272         else
1273                 typestr = "groupquota";
1274 
1275         if (domain == NULL || *domain == '\0') {
1276                 (void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN,
1277                     "%s@%llu", typestr, (longlong_t)rid);
1278         } else {
1279                 (void) snprintf(mpp->mp_name, ZFS_MAX_DATASET_NAME_LEN,
1280                     "%s@%s-%llu", typestr, domain, (longlong_t)rid);
1281         }
1282         (void) snprintf(mpp->mp_value, ZFS_MAXPROPLEN, "%llu", space);
1283         (void) strlcpy(mpp->mp_source, mhp->nh_dataset, ZFS_MAXPROPLEN);
1284 
1285         mhp->nh_count++;
1286         return (0);
1287 }
1288 
1289 /*
1290  * Callback to count each ZFS property
1291  */
1292 /*ARGSUSED*/
1293 static int
1294 zfs_count_prop_cb(int prop, void *pp)
1295 {
1296         (*(int *)pp)++;
1297         return (ZPROP_CONT);
1298 }
1299 
1300 /*
1301  * Callback to count each ZFS user/group quota
1302  */
1303 /*ARGSUSED*/
1304 static int
1305 zfs_count_quota_cb(void *pp, const char *domain, uid_t rid, uint64_t space)
1306 {
1307         (*(int *)pp)++;
1308         return (0);
1309 }
1310 
1311 /*
1312  * Count the number of ZFS properties and user/group quotas
1313  */
1314 int
1315 zfs_get_prop_counts(zfs_handle_t *zhp)
1316 {
1317         int count = 0;
1318         nvlist_t *uprops;
1319         nvpair_t *elp;
1320 
1321         if (zhp == NULL)
1322                 return (0);
1323 
1324         (void) zprop_iter(zfs_count_prop_cb, &count, TRUE, TRUE,
1325             ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
1326 
1327         (void) zfs_userspace(zhp, ZFS_PROP_USERQUOTA, zfs_count_quota_cb,
1328             &count);
1329         (void) zfs_userspace(zhp, ZFS_PROP_GROUPQUOTA, zfs_count_quota_cb,
1330             &count);
1331 
1332         uprops = zfs_get_user_props(zhp);
1333 
1334         elp = nvlist_next_nvpair(uprops, NULL);
1335         for (; elp != NULL; elp = nvlist_next_nvpair(uprops, elp))
1336                 count++;
1337 
1338         return (count);
1339 }
1340 
1341 /*
1342  * Notifies ndmpd that the metadata associated with the given ZFS dataset
1343  * should be backed up.
1344  */
1345 int
1346 ndmp_include_zfs(ndmp_context_t *nctx, const char *dataset)
1347 {
1348         tlm_commands_t *cmds;
1349         ndmp_metadata_handle_t mhd;
1350         ndmp_metadata_header_ext_t *mhp;
1351         ndmp_metadata_property_ext_t *mpp;
1352         zfs_handle_t *zhp;
1353         tlm_cmd_t *lcmd;
1354         long actual_size;
1355         nvlist_t *uprops, *ulist;
1356         const char *pname;
1357         nvpair_t *elp;
1358         char *sval, *ssrc;
1359         char *wbuf, *pp, *tp;
1360         long size, lsize, sz;
1361         int align = RECORDSIZE - 1;
1362         int pcount;
1363 
1364         if (nctx == NULL || (cmds = (tlm_commands_t *)nctx->nc_cmds) == NULL)
1365                 return (-1);
1366 
1367         if ((lcmd = cmds->tcs_command) == NULL ||
1368             lcmd->tc_buffers == NULL)
1369                 return (-1);
1370 
1371         (void) mutex_lock(&zlib_mtx);
1372         if ((zhp = zfs_open(zlibh, dataset, ZFS_TYPE_DATASET)) == NULL) {
1373                 (void) mutex_unlock(&zlib_mtx);
1374                 return (-1);
1375         }
1376 
1377         pcount = zfs_get_prop_counts(zhp);
1378         size = sizeof (ndmp_metadata_header_ext_t) +
1379             pcount * sizeof (ndmp_metadata_property_ext_t);
1380 
1381         size += align;
1382         size &= ~align;
1383 
1384         if ((mhp = malloc(size)) == NULL) {
1385                 zfs_close(zhp);
1386                 (void) mutex_unlock(&zlib_mtx);
1387                 return (-1);
1388         }
1389 
1390         (void) memset(mhp, 0, size);
1391 
1392         mhd.ml_handle = zhp;
1393         mhd.ml_xhdr = mhp;
1394         mhp->nh_total_bytes = size;
1395         mhp->nh_major = META_HDR_MAJOR_VERSION;
1396         mhp->nh_minor = META_HDR_MINOR_VERSION;
1397         mhp->nh_plversion = nctx->nc_plversion;
1398 
1399         (void) strlcpy(mhp->nh_plname, nctx->nc_plname,
1400             sizeof (mhp->nh_plname));
1401         (void) strlcpy(mhp->nh_magic, ZFS_META_MAGIC_EXT,
1402             sizeof (mhp->nh_magic));
1403         (void) strlcpy(mhp->nh_dataset, dataset, sizeof (mhp->nh_dataset));
1404 
1405         /* Get all the ZFS properties */
1406         (void) zprop_iter(zfs_put_prop_cb, &mhd, TRUE, TRUE,
1407             ZFS_TYPE_VOLUME | ZFS_TYPE_DATASET);
1408 
1409         /* Get user properties */
1410         uprops = zfs_get_user_props(mhd.ml_handle);
1411 
1412         elp = nvlist_next_nvpair(uprops, NULL);
1413 
1414         while (elp != NULL) {
1415                 mpp = &mhp->nh_property[mhp->nh_count];
1416                 if (nvpair_value_nvlist(elp, &ulist) != 0 ||
1417                     nvlist_lookup_string(ulist, ZPROP_VALUE, &sval) != 0 ||
1418                     nvlist_lookup_string(ulist, ZPROP_SOURCE, &ssrc) != 0) {
1419                         zfs_close(mhd.ml_handle);
1420                         (void) mutex_unlock(&zlib_mtx);
1421                         free(mhp);
1422                         return (-1);
1423                 }
1424                 if ((pname = nvpair_name(elp)) != NULL) {
1425                         (void) strlcpy(mpp->mp_name, pname,
1426                             ZFS_MAX_DATASET_NAME_LEN);
1427                 }
1428 
1429                 (void) strlcpy(mpp->mp_value, sval, ZFS_MAXPROPLEN);
1430                 (void) strlcpy(mpp->mp_source, ssrc, ZFS_MAXPROPLEN);
1431                 mhp->nh_count++;
1432                 elp = nvlist_next_nvpair(uprops, elp);
1433         }
1434 
1435         mhd.ml_quota_prop = ZFS_PROP_USERQUOTA;
1436         (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_USERQUOTA,
1437             zfs_put_quota_cb, &mhd);
1438         mhd.ml_quota_prop = ZFS_PROP_GROUPQUOTA;
1439         (void) zfs_userspace(mhd.ml_handle, ZFS_PROP_GROUPQUOTA,
1440             zfs_put_quota_cb, &mhd);
1441         mhp->nh_count = pcount;
1442 
1443         zfs_close(mhd.ml_handle);
1444         (void) mutex_unlock(&zlib_mtx);
1445 
1446         if ((wbuf = get_write_buffer(size, &actual_size, TRUE,
1447             lcmd)) != NULL) {
1448                 pp = (char *)mhp;
1449 
1450                 (void) memcpy(wbuf, pp, (actual_size < size) ?
1451                     actual_size : size);
1452                 pp += (actual_size < size) ? actual_size : size;
1453 
1454                 sz = actual_size;
1455                 while (sz < size &&
1456                     ((tp = get_write_buffer(size - sz, &lsize,
1457                     TRUE, lcmd))) != NULL) {
1458                         (void) memcpy(tp, pp, lsize);
1459                         sz += lsize;
1460                         pp += lsize;
1461                 }
1462                 if (sz > size) {
1463                         tlm_unget_write_buffer(lcmd->tc_buffers, sz - size);
1464                 }
1465         }
1466 
1467         free(mhp);
1468         return (0);
1469 }