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