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